TianaiCaptcha 开源验证码简单分析
7 分钟
滑块验证码参数
- 验证码的 ID:SLIDER_ff970847732c44859fb56935fab7f7c9
- 鼠标 move 的轨迹,一共记录 36 次
- 滑块从开始到结束的时间
ImageCaptchaTrack(bgImageWidth=300, bgImageHeight=180, templateImageWidth=null, templateImageHeight=null, startTime=Tue Sep 09 17:30:21 CST 2025, stopTime=Tue Sep 09 17:30:24 CST 2025, left=null, top=null, trackList=[ImageCaptchaTrack.Track(x=0.0, y=0.0, t=1244.0, type=down), ImageCaptchaTrack.Track(x=1.0, y=0.0, t=1268.0, type=move), ImageCaptchaTrack.Track(x=3.0, y=0.0, t=1284.0, type=move), ImageCaptchaTrack.Track(x=10.0, y=0.0, t=1301.0, type=move), ImageCaptchaTrack.Track(x=19.0, y=0.0, t=1318.0, type=move), ImageCaptchaTrack.Track(x=34.0, y=0.0, t=1334.0, type=move), ImageCaptchaTrack.Track(x=46.0, y=0.0, t=1351.0, type=move), ImageCaptchaTrack.Track(x=55.0, y=0.0, t=1368.0, type=move), ImageCaptchaTrack.Track(x=63.0, y=-1.0, t=1384.0, type=move), ImageCaptchaTrack.Track(x=75.0, y=-1.0, t=1401.0, type=move), ImageCaptchaTrack.Track(x=91.0, y=-1.0, t=1418.0, type=move), ImageCaptchaTrack.Track(x=113.0, y=-1.0, t=1435.0, type=move), ImageCaptchaTrack.Track(x=122.0, y=-1.0, t=1451.0, type=move), ImageCaptchaTrack.Track(x=132.0, y=-1.0, t=1468.0, type=move), ImageCaptchaTrack.Track(x=143.0, y=-1.0, t=1485.0, type=move), ImageCaptchaTrack.Track(x=156.0, y=-2.0, t=1501.0, type=move), ImageCaptchaTrack.Track(x=166.0, y=-2.0, t=1518.0, type=move), ImageCaptchaTrack.Track(x=172.0, y=-3.0, t=1535.0, type=move), ImageCaptchaTrack.Track(x=173.0, y=-3.0, t=1551.0, type=move), ImageCaptchaTrack.Track(x=174.0, y=-3.0, t=1568.0, type=move), ImageCaptchaTrack.Track(x=176.0, y=-3.0, t=1585.0, type=move), ImageCaptchaTrack.Track(x=182.0, y=-3.0, t=1602.0, type=move), ImageCaptchaTrack.Track(x=193.0, y=-3.0, t=1618.0, type=move), ImageCaptchaTrack.Track(x=206.0, y=-3.0, t=1635.0, type=move), ImageCaptchaTrack.Track(x=217.0, y=-3.0, t=1652.0, type=move), ImageCaptchaTrack.Track(x=218.0, y=-3.0, t=1668.0, type=move), ImageCaptchaTrack.Track(x=219.0, y=-3.0, t=1685.0, type=move), ImageCaptchaTrack.Track(x=220.0, y=-3.0, t=1701.0, type=move), ImageCaptchaTrack.Track(x=220.0, y=-4.0, t=1718.0, type=move), ImageCaptchaTrack.Track(x=221.0, y=-4.0, t=1735.0, type=move), ImageCaptchaTrack.Track(x=222.0, y=-4.0, t=1751.0, type=move), ImageCaptchaTrack.Track(x=221.0, y=-4.0, t=1835.0, type=move), ImageCaptchaTrack.Track(x=220.0, y=-4.0, t=2002.0, type=move), ImageCaptchaTrack.Track(x=218.0, y=-4.0, t=2018.0, type=move), ImageCaptchaTrack.Track(x=217.0, y=-3.0, t=2035.0, type=move), ImageCaptchaTrack.Track(x=218.0, y=-3.0, t=2369.0, type=move), ImageCaptchaTrack.Track(x=218.0, y=-3.0, t=2659.0, type=up)], data=null) 点选验证码参数
- 验证码的 ID:SLIDER_ff970847732c44859fb56935fab7f7c9
- 鼠标 move 的轨迹,一共记录 225 次
- 滑块从开始到结束的时间
ImageCaptchaTrack(bgImageWidth=300, bgImageHeight=180, templateImageWidth=null, templateImageHeight=null, startTime=Tue Sep 09 17:39:50 CST 2025, stopTime=Tue Sep 09 17:40:04 CST 2025, left=null, top=null, trackList=[ImageCaptchaTrack.Track(x=23.0, y=157.0, t=7061.0, type=click), ImageCaptchaTrack.Track(x=8.0, y=87.0, t=7133.0, type=move), ImageCaptchaTrack.Track(x=14.0, y=83.0, t=7142.0, type=move), ImageCaptchaTrack.Track(x=30.0, y=75.0, t=7159.0, type=move), ImageCaptchaTrack.Track(x=47.0, y=65.0, t=7176.0, type=move), ImageCaptchaTrack.Track(x=63.0, y=55.0, t=7193.0, type=move), ImageCaptchaTrack.Track(x=73.0, y=47.0, t=7209.0, type=move), ImageCaptchaTrack.Track(x=81.0, y=40.0, t=7226.0, type=move), ImageCaptchaTrack.Track(x=87.0, y=35.0, t=7243.0, type=move), ImageCaptchaTrack.Track(x=91.0, y=31.0, t=7259.0, type=move), ImageCaptchaTrack.Track(x=92.0, y=30.0, t=7276.0, type=move), ImageCaptchaTrack.Track(x=93.0, y=30.0, t=7293.0, type=move), ImageCaptchaTrack.Track(x=92.0, y=29.0, t=7454.0, type=move), ImageCaptchaTrack.Track(x=90.0, y=27.0, t=7461.0, type=move), ImageCaptchaTrack.Track(x=88.0, y=25.0, t=7476.0, type=move), ImageCaptchaTrack.Track(x=83.0, y=21.0, t=7493.0, type=move), ImageCaptchaTrack.Track(x=79.0, y=13.0, t=7509.0, type=move), ImageCaptchaTrack.Track(x=76.0, y=8.0, t=7526.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=4.0, t=7543.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=1.0, t=7560.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=-1.0, t=7576.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=-2.0, t=7593.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=-4.0, t=7609.0, type=move), ImageCaptchaTrack.Track(x=78.0, y=-6.0, t=7626.0, type=move), ImageCaptchaTrack.Track(x=84.0, y=-10.0, t=7643.0, type=move), ImageCaptchaTrack.Track(x=91.0, y=-12.0, t=7660.0, type=move), ImageCaptchaTrack.Track(x=97.0, y=-12.0, t=7676.0, type=move), ImageCaptchaTrack.Track(x=106.0, y=-12.0, t=7693.0, type=move), ImageCaptchaTrack.Track(x=122.0, y=-8.0, t=7710.0, type=move), ImageCaptchaTrack.Track(x=129.0, y=-7.0, t=7726.0, type=move), ImageCaptchaTrack.Track(x=134.0, y=-7.0, t=7743.0, type=move), ImageCaptchaTrack.Track(x=137.0, y=-7.0, t=7760.0, type=move), ImageCaptchaTrack.Track(x=139.0, y=-7.0, t=7777.0, type=move), ImageCaptchaTrack.Track(x=141.0, y=-7.0, t=7793.0, type=move), ImageCaptchaTrack.Track(x=143.0, y=-8.0, t=7810.0, type=move), ImageCaptchaTrack.Track(x=144.0, y=-9.0, t=7826.0, type=move), ImageCaptchaTrack.Track(x=145.0, y=-10.0, t=7845.0, type=move), ImageCaptchaTrack.Track(x=145.0, y=-11.0, t=7894.0, type=move), ImageCaptchaTrack.Track(x=145.0, y=-12.0, t=7917.0, type=move), ImageCaptchaTrack.Track(x=146.0, y=-12.0, t=7934.0, type=move), ImageCaptchaTrack.Track(x=147.0, y=-12.0, t=7943.0, type=move), ImageCaptchaTrack.Track(x=154.0, y=-12.0, t=7960.0, type=move), ImageCaptchaTrack.Track(x=161.0, y=-13.0, t=7977.0, type=move), ImageCaptchaTrack.Track(x=166.0, y=-13.0, t=7993.0, type=move), ImageCaptchaTrack.Track(x=167.0, y=-13.0, t=8010.0, type=move), ImageCaptchaTrack.Track(x=168.0, y=-13.0, t=8027.0, type=move), ImageCaptchaTrack.Track(x=169.0, y=-13.0, t=8318.0, type=move), ImageCaptchaTrack.Track(x=170.0, y=-13.0, t=8327.0, type=move), ImageCaptchaTrack.Track(x=171.0, y=-13.0, t=8344.0, type=move), ImageCaptchaTrack.Track(x=172.0, y=-13.0, t=8365.0, type=move), ImageCaptchaTrack.Track(x=178.0, y=-11.0, t=8430.0, type=move), ImageCaptchaTrack.Track(x=182.0, y=-10.0, t=8444.0, type=move), ImageCaptchaTrack.Track(x=195.0, y=-7.0, t=8460.0, type=move), ImageCaptchaTrack.Track(x=210.0, y=-6.0, t=8477.0, type=move), ImageCaptchaTrack.Track(x=214.0, y=-5.0, t=8494.0, type=move), ImageCaptchaTrack.Track(x=214.0, y=-4.0, t=8549.0, type=move), ImageCaptchaTrack.Track(x=212.0, y=-4.0, t=8573.0, type=move), ImageCaptchaTrack.Track(x=208.0, y=-3.0, t=8581.0, type=move), ImageCaptchaTrack.Track(x=205.0, y=-3.0, t=8594.0, type=move), ImageCaptchaTrack.Track(x=198.0, y=-2.0, t=8611.0, type=move), ImageCaptchaTrack.Track(x=193.0, y=-2.0, t=8627.0, type=move), ImageCaptchaTrack.Track(x=190.0, y=-2.0, t=8644.0, type=move), ImageCaptchaTrack.Track(x=188.0, y=-2.0, t=8661.0, type=move), ImageCaptchaTrack.Track(x=186.0, y=-2.0, t=8677.0, type=move), ImageCaptchaTrack.Track(x=185.0, y=-2.0, t=8694.0, type=move), ImageCaptchaTrack.Track(x=192.0, y=-2.0, t=8744.0, type=move), ImageCaptchaTrack.Track(x=206.0, y=-2.0, t=8761.0, type=move), ImageCaptchaTrack.Track(x=221.0, y=-2.0, t=8778.0, type=move), ImageCaptchaTrack.Track(x=231.0, y=-2.0, t=8794.0, type=move), ImageCaptchaTrack.Track(x=236.0, y=-3.0, t=8811.0, type=move), ImageCaptchaTrack.Track(x=237.0, y=-3.0, t=8862.0, type=move), ImageCaptchaTrack.Track(x=238.0, y=-3.0, t=8885.0, type=move), ImageCaptchaTrack.Track(x=239.0, y=-4.0, t=8894.0, type=move), ImageCaptchaTrack.Track(x=240.0, y=-5.0, t=8911.0, type=move), ImageCaptchaTrack.Track(x=242.0, y=-6.0, t=8927.0, type=move), ImageCaptchaTrack.Track(x=243.0, y=-7.0, t=8944.0, type=move), ImageCaptchaTrack.Track(x=245.0, y=-9.0, t=8961.0, type=move), ImageCaptchaTrack.Track(x=246.0, y=-9.0, t=8978.0, type=move), ImageCaptchaTrack.Track(x=248.0, y=-10.0, t=8994.0, type=move), ImageCaptchaTrack.Track(x=251.0, y=-10.0, t=9011.0, type=move), ImageCaptchaTrack.Track(x=256.0, y=-10.0, t=9028.0, type=move), ImageCaptchaTrack.Track(x=260.0, y=-10.0, t=9044.0, type=move), ImageCaptchaTrack.Track(x=264.0, y=-10.0, t=9061.0, type=move), ImageCaptchaTrack.Track(x=265.0, y=-10.0, t=9078.0, type=move), ImageCaptchaTrack.Track(x=264.0, y=-9.0, t=9237.0, type=move), ImageCaptchaTrack.Track(x=279.0, y=60.0, t=9325.0, type=click), ImageCaptchaTrack.Track(x=263.0, y=-8.0, t=9382.0, type=move), ImageCaptchaTrack.Track(x=255.0, y=-6.0, t=9395.0, type=move), ImageCaptchaTrack.Track(x=240.0, y=-5.0, t=9412.0, type=move), ImageCaptchaTrack.Track(x=224.0, y=-5.0, t=9428.0, type=move), ImageCaptchaTrack.Track(x=210.0, y=-5.0, t=9445.0, type=move), ImageCaptchaTrack.Track(x=193.0, y=-5.0, t=9461.0, type=move), ImageCaptchaTrack.Track(x=187.0, y=-6.0, t=9478.0, type=move), ImageCaptchaTrack.Track(x=183.0, y=-7.0, t=9495.0, type=move), ImageCaptchaTrack.Track(x=180.0, y=-8.0, t=9511.0, type=move), ImageCaptchaTrack.Track(x=178.0, y=-8.0, t=9528.0, type=move), ImageCaptchaTrack.Track(x=177.0, y=-8.0, t=9545.0, type=move), ImageCaptchaTrack.Track(x=174.0, y=-9.0, t=9562.0, type=move), ImageCaptchaTrack.Track(x=172.0, y=-9.0, t=9578.0, type=move), ImageCaptchaTrack.Track(x=168.0, y=-10.0, t=9595.0, type=move), ImageCaptchaTrack.Track(x=166.0, y=-10.0, t=9612.0, type=move), ImageCaptchaTrack.Track(x=163.0, y=-12.0, t=9628.0, type=move), ImageCaptchaTrack.Track(x=162.0, y=-12.0, t=9646.0, type=move), ImageCaptchaTrack.Track(x=161.0, y=-12.0, t=9662.0, type=move), ImageCaptchaTrack.Track(x=160.0, y=-12.0, t=9694.0, type=move), ImageCaptchaTrack.Track(x=159.0, y=-12.0, t=9710.0, type=move), ImageCaptchaTrack.Track(x=158.0, y=-12.0, t=9745.0, type=move), ImageCaptchaTrack.Track(x=157.0, y=-12.0, t=9814.0, type=move), ImageCaptchaTrack.Track(x=172.0, y=57.0, t=9893.0, type=click), ImageCaptchaTrack.Track(x=155.0, y=-12.0, t=9974.0, type=move), ImageCaptchaTrack.Track(x=146.0, y=-12.0, t=9981.0, type=move), ImageCaptchaTrack.Track(x=135.0, y=-12.0, t=9995.0, type=move), ImageCaptchaTrack.Track(x=104.0, y=-12.0, t=10012.0, type=move), ImageCaptchaTrack.Track(x=81.0, y=-12.0, t=10029.0, type=move), ImageCaptchaTrack.Track(x=66.0, y=-12.0, t=10045.0, type=move), ImageCaptchaTrack.Track(x=69.0, y=-7.0, t=10126.0, type=move), ImageCaptchaTrack.Track(x=72.0, y=-2.0, t=10133.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=3.0, t=10145.0, type=move), ImageCaptchaTrack.Track(x=82.0, y=15.0, t=10162.0, type=move), ImageCaptchaTrack.Track(x=90.0, y=26.0, t=10179.0, type=move), ImageCaptchaTrack.Track(x=98.0, y=35.0, t=10196.0, type=move), ImageCaptchaTrack.Track(x=107.0, y=44.0, t=10212.0, type=move), ImageCaptchaTrack.Track(x=112.0, y=49.0, t=10229.0, type=move), ImageCaptchaTrack.Track(x=122.0, y=56.0, t=10246.0, type=move), ImageCaptchaTrack.Track(x=129.0, y=61.0, t=10262.0, type=move), ImageCaptchaTrack.Track(x=134.0, y=66.0, t=10279.0, type=move), ImageCaptchaTrack.Track(x=137.0, y=70.0, t=10296.0, type=move), ImageCaptchaTrack.Track(x=138.0, y=71.0, t=10312.0, type=move), ImageCaptchaTrack.Track(x=138.0, y=72.0, t=10329.0, type=move), ImageCaptchaTrack.Track(x=137.0, y=72.0, t=10389.0, type=move), ImageCaptchaTrack.Track(x=135.0, y=72.0, t=10405.0, type=move), ImageCaptchaTrack.Track(x=133.0, y=72.0, t=10422.0, type=move), ImageCaptchaTrack.Track(x=132.0, y=71.0, t=10438.0, type=move), ImageCaptchaTrack.Track(x=131.0, y=70.0, t=10446.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=69.0, t=10462.0, type=move), ImageCaptchaTrack.Track(x=129.0, y=68.0, t=10479.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=68.0, t=10589.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=69.0, t=10629.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=70.0, t=10654.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=71.0, t=10663.0, type=move), ImageCaptchaTrack.Track(x=130.0, y=72.0, t=10765.0, type=move), ImageCaptchaTrack.Track(x=128.0, y=74.0, t=10813.0, type=move), ImageCaptchaTrack.Track(x=122.0, y=74.0, t=10829.0, type=move), ImageCaptchaTrack.Track(x=114.0, y=72.0, t=10846.0, type=move), ImageCaptchaTrack.Track(x=107.0, y=69.0, t=10863.0, type=move), ImageCaptchaTrack.Track(x=101.0, y=64.0, t=10880.0, type=move), ImageCaptchaTrack.Track(x=97.0, y=62.0, t=10896.0, type=move), ImageCaptchaTrack.Track(x=92.0, y=58.0, t=10913.0, type=move), ImageCaptchaTrack.Track(x=89.0, y=55.0, t=10930.0, type=move), ImageCaptchaTrack.Track(x=86.0, y=52.0, t=10946.0, type=move), ImageCaptchaTrack.Track(x=83.0, y=51.0, t=10963.0, type=move), ImageCaptchaTrack.Track(x=82.0, y=50.0, t=10980.0, type=move), ImageCaptchaTrack.Track(x=82.0, y=49.0, t=10998.0, type=move), ImageCaptchaTrack.Track(x=81.0, y=49.0, t=11046.0, type=move), ImageCaptchaTrack.Track(x=79.0, y=48.0, t=11063.0, type=move), ImageCaptchaTrack.Track(x=76.0, y=46.0, t=11080.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=45.0, t=11096.0, type=move), ImageCaptchaTrack.Track(x=71.0, y=43.0, t=11113.0, type=move), ImageCaptchaTrack.Track(x=71.0, y=44.0, t=11190.0, type=move), ImageCaptchaTrack.Track(x=73.0, y=47.0, t=11197.0, type=move), ImageCaptchaTrack.Track(x=77.0, y=52.0, t=11213.0, type=move), ImageCaptchaTrack.Track(x=80.0, y=57.0, t=11230.0, type=move), ImageCaptchaTrack.Track(x=82.0, y=60.0, t=11247.0, type=move), ImageCaptchaTrack.Track(x=82.0, y=62.0, t=11264.0, type=move), ImageCaptchaTrack.Track(x=83.0, y=62.0, t=11293.0, type=move), ImageCaptchaTrack.Track(x=81.0, y=62.0, t=11382.0, type=move), ImageCaptchaTrack.Track(x=78.0, y=61.0, t=11398.0, type=move), ImageCaptchaTrack.Track(x=74.0, y=58.0, t=11413.0, type=move), ImageCaptchaTrack.Track(x=70.0, y=56.0, t=11430.0, type=move), ImageCaptchaTrack.Track(x=69.0, y=55.0, t=11447.0, type=move), ImageCaptchaTrack.Track(x=67.0, y=53.0, t=11464.0, type=move), ImageCaptchaTrack.Track(x=66.0, y=52.0, t=11480.0, type=move), ImageCaptchaTrack.Track(x=64.0, y=52.0, t=11497.0, type=move), ImageCaptchaTrack.Track(x=64.0, y=51.0, t=11514.0, type=move), ImageCaptchaTrack.Track(x=63.0, y=50.0, t=11530.0, type=move), ImageCaptchaTrack.Track(x=62.0, y=48.0, t=11547.0, type=move), ImageCaptchaTrack.Track(x=61.0, y=46.0, t=11564.0, type=move), ImageCaptchaTrack.Track(x=60.0, y=44.0, t=11581.0, type=move), ImageCaptchaTrack.Track(x=58.0, y=43.0, t=11597.0, type=move), ImageCaptchaTrack.Track(x=59.0, y=43.0, t=11846.0, type=move), ImageCaptchaTrack.Track(x=60.0, y=42.0, t=11853.0, type=move), ImageCaptchaTrack.Track(x=61.0, y=42.0, t=11864.0, type=move), ImageCaptchaTrack.Track(x=62.0, y=42.0, t=11881.0, type=move), ImageCaptchaTrack.Track(x=62.0, y=41.0, t=11898.0, type=move), ImageCaptchaTrack.Track(x=63.0, y=41.0, t=11914.0, type=move), ImageCaptchaTrack.Track(x=62.0, y=40.0, t=12485.0, type=move), ImageCaptchaTrack.Track(x=61.0, y=39.0, t=12533.0, type=move), ImageCaptchaTrack.Track(x=67.0, y=41.0, t=13014.0, type=move), ImageCaptchaTrack.Track(x=80.0, y=43.0, t=13022.0, type=move), ImageCaptchaTrack.Track(x=95.0, y=46.0, t=13032.0, type=move), ImageCaptchaTrack.Track(x=133.0, y=52.0, t=13048.0, type=move), ImageCaptchaTrack.Track(x=167.0, y=57.0, t=13065.0, type=move), ImageCaptchaTrack.Track(x=208.0, y=61.0, t=13082.0, type=move), ImageCaptchaTrack.Track(x=240.0, y=63.0, t=13099.0, type=move), ImageCaptchaTrack.Track(x=265.0, y=63.0, t=13115.0, type=move), ImageCaptchaTrack.Track(x=279.0, y=63.0, t=13132.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=62.0, t=13149.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=61.0, t=13166.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=60.0, t=13190.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=59.0, t=13198.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=57.0, t=13215.0, type=move), ImageCaptchaTrack.Track(x=283.0, y=55.0, t=13232.0, type=move), ImageCaptchaTrack.Track(x=281.0, y=50.0, t=13249.0, type=move), ImageCaptchaTrack.Track(x=277.0, y=46.0, t=13266.0, type=move), ImageCaptchaTrack.Track(x=274.0, y=41.0, t=13282.0, type=move), ImageCaptchaTrack.Track(x=267.0, y=37.0, t=13299.0, type=move), ImageCaptchaTrack.Track(x=263.0, y=35.0, t=13315.0, type=move), ImageCaptchaTrack.Track(x=260.0, y=34.0, t=13332.0, type=move), ImageCaptchaTrack.Track(x=259.0, y=34.0, t=13349.0, type=move), ImageCaptchaTrack.Track(x=256.0, y=34.0, t=13366.0, type=move), ImageCaptchaTrack.Track(x=253.0, y=34.0, t=13382.0, type=move), ImageCaptchaTrack.Track(x=249.0, y=35.0, t=13399.0, type=move), ImageCaptchaTrack.Track(x=243.0, y=36.0, t=13416.0, type=move), ImageCaptchaTrack.Track(x=240.0, y=37.0, t=13432.0, type=move), ImageCaptchaTrack.Track(x=237.0, y=37.0, t=13449.0, type=move), ImageCaptchaTrack.Track(x=235.0, y=37.0, t=13465.0, type=move), ImageCaptchaTrack.Track(x=231.0, y=37.0, t=13482.0, type=move), ImageCaptchaTrack.Track(x=227.0, y=37.0, t=13499.0, type=move), ImageCaptchaTrack.Track(x=224.0, y=37.0, t=13516.0, type=move), ImageCaptchaTrack.Track(x=220.0, y=37.0, t=13532.0, type=move), ImageCaptchaTrack.Track(x=217.0, y=37.0, t=13549.0, type=move), ImageCaptchaTrack.Track(x=212.0, y=37.0, t=13566.0, type=move), ImageCaptchaTrack.Track(x=209.0, y=37.0, t=13582.0, type=move), ImageCaptchaTrack.Track(x=207.0, y=37.0, t=13599.0, type=move), ImageCaptchaTrack.Track(x=222.0, y=106.0, t=13758.0, type=click)], data=null) 简单校验
概述:
- 提供点击式验证码和滑动式验证码的验证机制
- 通过位置百分比计算和容忍度判断,验证用户操作的准确性
- 支持存储验证过程中的关键数据(目标值、实际值、偏差等)
点击验证码校验:
- 提取预设目标点信息(格式为 "x%,y%;x%,y%")
- 从轨迹中筛选出点击类型(
CLICK)的轨迹点 - 两种验证模式:
- 有序验证:按顺序匹配点击轨迹与目标点
- 无序验证:不限制顺序,只要每个目标点都有匹配的点击
- 通过百分比计算(相对背景图尺寸)和容忍度判断位置是否匹配
滑块验证码校验:
- 提取预设的目标滑动百分比
- 计算实际滑动距离(终点 X 坐标 - 起点 X 坐标)
- 将实际滑动距离转换为相对于背景图宽度的百分比
- 校验实际百分比与目标百分比是否在容忍范围内
public boolean doValidClickCaptcha(ImageCaptchaTrack imageCaptchaTrack,
AnyMap imageCaptchaValidData,
Float tolerant,
String type) {
String validStr = imageCaptchaValidData.getString(PERCENTAGE_KEY, null);
Object checkOrder = imageCaptchaValidData.getOrDefault(CLICK_IMAGE_CHECK_ORDER_KEY, true);
if (ObjectUtils.isEmpty(validStr)) {
return false;
}
String[] splitArr = validStr.split(";");
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
if (trackList.size() < splitArr.length) {
return false;
}
// 取出点击事件的轨迹数据
List<ImageCaptchaTrack.Track> clickTrackList = trackList
.stream()
.filter(t -> TrackTypeConstant.CLICK.equalsIgnoreCase(t.getType()))
.collect(Collectors.toList());
if (clickTrackList.size() != splitArr.length) {
return false;
}
StringBuilder sb = new StringBuilder();
List<Double> percentages = new ArrayList<>();
for (int i = 0; i < splitArr.length; i++) {
String posStr = splitArr[i];
String[] posArr = posStr.split(",");
float xPercentage = Float.parseFloat(posArr[0]);
float yPercentage = Float.parseFloat(posArr[1]);
float calcXPercentage = 0f;
float calcYPercentage = 0f;
if (Boolean.TRUE.equals(checkOrder)) {
ImageCaptchaTrack.Track track = clickTrackList.get(0);
calcXPercentage = calcPercentage(track.getX(), imageCaptchaTrack.getBgImageWidth());
calcYPercentage = calcPercentage(track.getY(), imageCaptchaTrack.getBgImageHeight());
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
return false;
}
clickTrackList.remove(0);
} else {
boolean flag = false;
for (int a = 0; a < clickTrackList.size(); a++) {
ImageCaptchaTrack.Track track = clickTrackList.get(a);
calcXPercentage = calcPercentage(track.getX(), imageCaptchaTrack.getBgImageWidth());
calcYPercentage = calcPercentage(track.getY(), imageCaptchaTrack.getBgImageHeight());
if (checkPercentage(calcXPercentage, xPercentage, tolerant)
&& checkPercentage(calcYPercentage, yPercentage, tolerant)) {
// 验证命中
clickTrackList.remove(a);
flag = true;
break;
}
}
if (!flag) {
return false;
}
}
if (i > 0) {
sb.append("|");
}
sb.append(calcXPercentage).append(",").append(calcYPercentage);
percentages.add((double) ((calcXPercentage - xPercentage) + (calcYPercentage - yPercentage)));
}
// 存储一下当前计算出来的值
return true;
}
public boolean doValidSliderCaptcha(ImageCaptchaTrack imageCaptchaTrack,
AnyMap imageCaptchaValidData,
Float tolerant,
String type) {
Float oriPercentage = imageCaptchaValidData.getFloat(PERCENTAGE_KEY);
if (oriPercentage == null) {
// 没读取到百分比
return false;
}
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
ImageCaptchaTrack.Track firstTrack = trackList.get(0);
// 取最后一个滑动轨迹
ImageCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
// 计算百分比
float calcPercentage = calcPercentage(lastTrack.getX() - firstTrack.getX(), imageCaptchaTrack.getBgImageWidth());
// 校验百分比
boolean percentage = checkPercentage(calcPercentage, oriPercentage, tolerant);
if (percentage) {
// 校验成功
// 存储一下当前计算出来的值
imageCaptchaValidData.put(USER_CURRENT_PERCENTAGE, String.valueOf(calcPercentage));
imageCaptchaValidData.put(USER_CURRENT_PERCENTAGE_STD, String.valueOf(calcPercentage - oriPercentage));
}
return percentage;
}
protected void addPercentage(ImageCaptchaInfo imageCaptchaInfo, AnyMap imageCaptchaValidData) {
float percentage = calcPercentage(imageCaptchaInfo.getRandomX(), imageCaptchaInfo.getBackgroundImageWidth());
imageCaptchaValidData.put(PERCENTAGE_KEY, percentage);
}
} 复杂轨迹校验
// 遍历轨迹列表
Iterator var2 = imageCaptchaTrack.getTrackList().iterator();
do {
if (!var2.hasNext()) {
return; // 所有轨迹点都校验通过
}
ImageCaptchaTrack.Track track = (ImageCaptchaTrack.Track)var2.next();
x = track.getX(); // X坐标
y = track.getY(); // Y坐标
t = track.getT(); // 时间戳
type = track.getType();// 轨迹类型
// 只要有一个轨迹点的任何属性为空,就抛出异常
} while(x != null && y != null && t != null && !ObjectUtils.isEmpty(type));
throw new IllegalArgumentException("track[x,y,t,type] must not be null"); 根据上文获取到的坐标行为轨迹,做的校验:
- 滑动时间验证:检查滑动开始到结束的时间是否过短(小于 300 毫秒)
- 轨迹点数量验证:轨迹点数量需满足
10 ≤ 数量 ≤ 背景图宽度×5,太少(<10)可能是简单脚本,太多(> 宽度 ×5)可能是异常数据。 - 初始位置验证:x 轴和 y 轴应该是从 0 开始的,要是一开始 x 轴和 y 轴乱跑,返回 false
- 轨迹连续性与合理性验证:
- 相邻轨迹点的 X 或 Y 方向位移不能超过 50 像素(防止瞬间跳变,真人滑动有速度限制);
- 统计 Y 坐标不变的点(机器可能水平匀速滑动,真人难免有上下波动);
- 统计 X 坐标超出背景图宽度的点(正常滑动不会越界,过多越界点为异常)
- 滑动速度变化验证:
- 验证逻辑:对比滑动过程中前 70% 轨迹与后 30% 轨迹的平均时间间隔。
- 判断标准:真人滑动通常越到后期速度越快(后 30% 平均时间间隔 > 前 70%),若不符合此特征(如匀速或减速),则判定为异常。
public ApiResponse<?> afterValid(Boolean basicValid, ImageCaptchaTrack imageCaptchaTrack, AnyMap captchaValidData, Float tolerant, String type) {
// 如果基础验证未通过,直接返回成功(无需二次验证)
if (!basicValid) {
return ApiResponse.ofSuccess();
// 如果不是滑块验证码类型,直接返回成功(无需验证)
} else if (!CaptchaTypeClassifier.isSliderCaptcha(type)) {
return ApiResponse.ofSuccess();
}
long startSlidingTime = imageCaptchaTrack.getStartTime().getTime(); // 滑动开始时间
long endSlidingTime = imageCaptchaTrack.getStopTime().getTime(); // 滑动结束时间
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth(); // 背景图宽度
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList(); // 滑动轨迹点列表
// 如果滑动时间小于300毫秒(太快),判定为机器操作
if (startSlidingTime + 300L > endSlidingTime) {
return ApiResponse.ofMessage(DEFINITION);
}
// 轨迹点数量需在 [10, 背景图宽度*5] 范围内
else if (trackList.size() >= 10 && trackList.size() <= bgImageWidth * 5) {
// 轨迹点数量合理,进入下一步验证
} else {
// 轨迹点太少(<10)或太多(>宽度*5),判定为异常
return ApiResponse.ofMessage(DEFINITION);
}
ImageCaptchaTrack.Track firstTrack = trackList.get(0); // 第一个轨迹点
// 检查初始位置是否在 [(-10,-10), (10,10)] 范围内(接近起点)
if (!(firstTrack.getX() > 10.0F) && !(firstTrack.getX() < -10.0F) &&
!(firstTrack.getY() > 10.0F) && !(firstTrack.getY() < -10.0F)) {
// 初始位置合理,进入下一步验证
} else {
// 初始位置偏离起点过远,判定为异常
return ApiResponse.ofMessage(DEFINITION);
}
int check4 = 0; // 记录Y坐标与初始Y相同的轨迹点数量
int check7 = 0; // 记录X坐标超出背景图宽度的轨迹点数量
for(i = 1; i < trackList.size(); ++i) {
track = trackList.get(i);
x = track.getX();
y = track.getY();
// 统计Y坐标未变化的点(机器可能水平滑动,Y值不变)
if (firstTrack.getY() == y) {
++check4;
}
// 统计X坐标超出背景图宽度的点(异常越界)
if (x >= bgImageWidth) {
++check7;
}
// 检查相邻轨迹点的位移是否过大(单次移动>50像素)
preTrack = trackList.get(i - 1);
if (track.getX() - preTrack.getX() > 50.0F ||
track.getY() - preTrack.getY() > 50.0F) {
return ApiResponse.ofMessage(DEFINITION); // 位移过大,判定为异常
}
}
// 条件1:Y坐标不变的点数量≠总轨迹点数量(排除完全水平滑动)
// 条件2:越界点数量≤200(允许少量异常,但不能过多)
if (check4 != trackList.size() && check7 <= 200) {
// 取轨迹的前70%和后30%,计算两段的平均时间间隔
int i = (int)(trackList.size() * 0.7);
ImageCaptchaTrack.Track track70 = trackList.get(i - 1);
float avgTimeFirst70 = track70.getT() / i; // 前70%轨迹的平均时间
ImageCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
double avgTimeLast30 = lastTrack.getT() / (trackList.size() - i); // 后30%轨迹的平均时间
// 真人滑动通常会越到后面越快(平均时间间隔增大)
if (avgTimeLast30 > avgTimeFirst70) {
return ApiResponse.ofSuccess(); // 符合真人特征,验证通过
} else {
return ApiResponse.ofMessage(DEFINITION); // 速度变化异常,验证失败
}
} else {
return ApiResponse.ofMessage(DEFINITION); // 异常点比例过高,验证失败
}
} ~ ~ The End ~ ~
文章标题:TianaiCaptcha 开源验证码简单分析
文章链接:https://www.aiwin.net.cn/index.php/archives/4518/
最后编辑:2025 年 10 月 9 日 17:44 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)