乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      從12306網(wǎng)站新驗證碼看Web驗證碼設(shè)計與破解

       新華書店好書榜 2015-04-24
       2015年3月16日,鐵路官方購票網(wǎng)站12306又出新招,在登錄界面推出了全新的驗證方式,用戶在填寫好登錄名和密碼之后,還要準確的選取圖片驗證碼才能登陸成功。據(jù)悉,12306驗證碼改版后,目前所有搶票工具都已經(jīng)無法登錄。

      多么慘絕人寰的消息,小編相信各大互聯(lián)網(wǎng)公司都在潛心鉆研新的搶票助手,來破解全新的驗證碼模式。

      下面小編帶大家看看各種驗證碼的設(shè)計原理及其破解方法。

      首先是純文本式驗證碼,是比較原始的一種。

       




      這種驗證碼并不符合驗證碼的定義,因為只有自動生成的問題才能用做驗證碼,這種文字驗證碼都是從題庫里選擇出來的,數(shù)量有限。破解方式也很簡單,多 刷新幾次,建立題庫和對應的答案,用正則從網(wǎng)頁里抓取問題,尋找匹配的答案后破解。也有些用隨機生成的數(shù)學公式,比如 隨機數(shù) [+-*/]隨機運算符 隨機數(shù)=?,小學生水平的程序員也可以搞定……

      這種驗證碼也不是一無是處,對于很多見到表單就來一發(fā)的spam bot來說,實在沒必要單獨為了一個網(wǎng)站下那么大功夫。對于鐵了心要在你的網(wǎng)站大量灌水的人,這種驗證碼和沒有一樣。

      第二個是目前比較主流的圖片驗證碼:

       





      這類圖片驗證碼的原理就是通過字符的粘連增加及其識別的難度,而上邊這種一般用于不大的網(wǎng)站。

      這類驗證碼處理方式:

      圖片預處理

      怎么去掉背景干擾呢?可以注意到每個驗證碼數(shù)字或字母都是同一顏色,所以把驗證碼平均分成5份

      計算每個區(qū)域的顏色分布,除了白色之外,顏色值最多的就是驗證碼的顏色,因此很容易將背景去掉

       





      代碼:

      1.public static BufferedImage removeBackgroud(String picFile)  
      2.            throws Exception {  
      3.        BufferedImage img = ImageIO.read(new File(picFile));  
      4.        img = img.getSubimage(1, 1, img.getWidth() - 2, img.getHeight() - 2);  
      5.        int width = img.getWidth();  
      6.        int height = img.getHeight();  
      7.        double subWidth = (double) width / 5.0;  
      8.        for (int i = 0; i < 5; i++) {  
      9.            Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
      10.            for (int x = (int) (1 + i * subWidth); x < (i + 1) * subWidth  
      11.                    && x < width - 1; ++x) {  
      12.                for (int y = 0; y < height; ++y) {  
      13.                    if (isWhite(img.getRGB(x, y)) == 1)  
      14.                        continue;  
      15.                    if (map.containsKey(img.getRGB(x, y))) {  
      16.                        map.put(img.getRGB(x, y), map.get(img.getRGB(x, y)) + 1);  
      17.                    } else {  
      18.                        map.put(img.getRGB(x, y), 1);  
      19.                    }  
      20.                }  
      21.            }  
      22.            int max = 0;  
      23.            int colorMax = 0;  
      24.            for (Integer color : map.keySet()) {  
      25.                if (max < map.get(color)) {  
      26.                    max = map.get(color);  
      27.                    colorMax = color;  
      28.                }  
      29.            }  
      30.            for (int x = (int) (1 + i * subWidth); x < (i + 1) * subWidth  
      31.                    && x < width - 1; ++x) {  
      32.                for (int y = 0; y < height; ++y) {  
      33.                    if (img.getRGB(x, y) != colorMax) {  
      34.                        img.setRGB(x, y, Color.WHITE.getRGB());  
      35.                    } else {  
      36.                        img.setRGB(x, y, Color.BLACK.getRGB());  
      37.                    }  
      38.                }  
      39.            }  
      40.        }  
      41.        return img;  
      得到與下圖

       



      接著是對圖片進行縱向掃描進行切割。

       



      再對每一部分橫向掃描

       



      然后進行訓練

       




      最后因為固定大小,識別跟 驗證碼識別--1 里面一樣,像素比較就可以了。

      源碼:

      1.public class ImagePreProcess2 {  
      2.  
      3.    private static Map<BufferedImage, String> trainMap = null;  
      4.    private static int index = 0;  
      5.  
      6.    public static int isBlack(int colorInt) {  
      7.        Color color = new Color(colorInt);  
      8.        if (color.getRed() + color.getGreen() + color.getBlue() <= 100) {  
      9.            return 1;  
      10.        }  
      11.        return 0;  
      12.    }  
      13.  
      14.    public static int isWhite(int colorInt) {  
      15.        Color color = new Color(colorInt);  
      16.        if (color.getRed() + color.getGreen() + color.getBlue() > 100) {  
      17.            return 1;  
      18.        }  
      19.        return 0;  
      20.    }  
      21.  
      22.    public static BufferedImage removeBackgroud(String picFile)  
      23.            throws Exception {  
      24.        BufferedImage img = ImageIO.read(new File(picFile));  
      25.        return img;  
      26.    }  
      27.  
      28.    public static BufferedImage removeBlank(BufferedImage img) throws Exception {  
      29.        int width = img.getWidth();  
      30.        int height = img.getHeight();  
      31.        int start = 0;  
      32.        int end = 0;  
      33.        Label1: for (int y = 0; y < height; ++y) {  
      34.            int count = 0;  
      35.            for (int x = 0; x < width; ++x) {  
      36.                if (isWhite(img.getRGB(x, y)) == 1) {  
      37.                    count++;  
      38.                }  
      39.                if (count >= 1) {  
      40.                    start = y;  
      41.                    break Label1;  
      42.                }  
      43.            }  
      44.        }  
      45.        Label2: for (int y = height - 1; y >= 0; --y) {  
      46.            int count = 0;  
      47.            for (int x = 0; x < width; ++x) {  
      48.                if (isWhite(img.getRGB(x, y)) == 1) {  
      49.                    count++;  
      50.                }  
      51.                if (count >= 1) {  
      52.                    end = y;  
      53.                    break Label2;  
      54.                }  
      55.            }  
      56.        }  
      57.        return img.getSubimage(0, start, width, end - start + 1);  
      58.    }  
      59.  
      60.    public static List<BufferedImage> splitImage(BufferedImage img)  
      61.            throws Exception {  
      62.        List<BufferedImage> subImgs = new ArrayList<BufferedImage>();  
      63.        int width = img.getWidth();  
      64.        int height = img.getHeight();  
      65.        List<Integer> weightlist = new ArrayList<Integer>();  
      66.        for (int x = 0; x < width; ++x) {  
      67.            int count = 0;  
      68.            for (int y = 0; y < height; ++y) {  
      69.                if (isWhite(img.getRGB(x, y)) == 1) {  
      70.                    count++;  
      71.                }  
      72.            }  
      73.            weightlist.add(count);  
      74.        }  
      75.        for (int i = 0; i < weightlist.size();) {  
      76.            int length = 0;  
      77.            while (weightlist.get(i++) > 1) {  
      78.                length++;  
      79.            }  
      80.            if (length > 12) {  
      81.                subImgs.add(removeBlank(img.getSubimage(i - length - 1, 0,  
      82.                        length / 2, height)));  
      83.                subImgs.add(removeBlank(img.getSubimage(i - length / 2 - 1, 0,  
      84.                        length / 2, height)));  
      85.            } else if (length > 3) {  
      86.                subImgs.add(removeBlank(img.getSubimage(i - length - 1, 0,  
      87.                        length, height)));  
      88.            }  
      89.        }  
      90.        return subImgs;  
      91.    }  
      92.  
      93.    public static Map<BufferedImage, String> loadTrainData() throws Exception {  
      94.        if (trainMap == null) {  
      95.            Map<BufferedImage, String> map = new HashMap<BufferedImage, String>();  
      96.            File dir = new File("train2");  
      97.            File[] files = dir.listFiles();  
      98.            for (File file : files) {  
      99.                map.put(ImageIO.read(file), file.getName().charAt(0) + "");  
      100.            }  
      101.            trainMap = map;  
      102.        }  
      103.        return trainMap;  
      104.    }  
      105.  
      106.    public static String getSingleCharOcr(BufferedImage img,  
      107.            Map<BufferedImage, String> map) {  
      108.        String result = "";  
      109.        int width = img.getWidth();  
      110.        int height = img.getHeight();  
      111.        int min = width * height;  
      112.        for (BufferedImage bi : map.keySet()) {  
      113.            int count = 0;  
      114.            int widthmin = width < bi.getWidth() ? width : bi.getWidth();  
      115.            int heightmin = height < bi.getHeight() ? height : bi.getHeight();  
      116.            Label1: for (int x = 0; x < widthmin; ++x) {  
      117.                for (int y = 0; y < heightmin; ++y) {  
      118.                    if (isWhite(img.getRGB(x, y)) != isWhite(bi.getRGB(x, y))) {  
      119.                        count++;  
      120.                        if (count >= min)  
      121.                            break Label1;  
      122.                    }  
      123.                }  
      124.            }  
      125.            if (count < min) {  
      126.                min = count;  
      127.                result = map.get(bi);  
      128.            }  
      129.        }  
      130.        return result;  
      131.    }  
      132.  
      133.    public static String getAllOcr(String file) throws Exception {  
      134.        BufferedImage img = removeBackgroud(file);  
      135.        List<BufferedImage> listImg = splitImage(img);  
      136.        Map<BufferedImage, String> map = loadTrainData();  
      137.        String result = "";  
      138.        for (BufferedImage bi : listImg) {  
      139.            result += getSingleCharOcr(bi, map);  
      140.        }  
      141.        ImageIO.write(img, "JPG", new File("result2//" + result + ".jpg"));  
      142.        return result;  
      143.    }  
      144.  
      145.    public static void downloadImage() {  
      146.        HttpClient httpClient = new HttpClient();  
      147.        GetMethod getMethod = null;  
      148.        for (int i = 0; i < 30; i++) {  
      149.            getMethod = new GetMethod("http://www./img.php?key="  
      150.                    + (2000 + i));  
      151.            try {  
      152.                // 執(zhí)行g(shù)etMethod  
      153.                int statusCode = httpClient.executeMethod(getMethod);  
      154.                if (statusCode != HttpStatus.SC_OK) {  
      155.                    System.err.println("Method failed: "  
      156.                            + getMethod.getStatusLine());  
      157.                }  
      158.                // 讀取內(nèi)容  
      159.                String picName = "img2//" + i + ".jpg";  
      160.                InputStream inputStream = getMethod.getResponseBodyAsStream();  
      161.                OutputStream outStream = new FileOutputStream(picName);  
      162.                IOUtils.copy(inputStream, outStream);  
      163.                outStream.close();  
      164.                System.out.println(i + "OK!");  
      165.            } catch (Exception e) {  
      166.                e.printStackTrace();  
      167.            } finally {  
      168.                // 釋放連接  
      169.                getMethod.releaseConnection();  
      170.            }  
      171.        }  
      172.    }  
      173.  
      174.    public static void trainData() throws Exception {  
      175.        File dir = new File("temp");  
      176.        File[] files = dir.listFiles();  
      177.        for (File file : files) {  
      178.            BufferedImage img = removeBackgroud("temp//" + file.getName());  
      179.            List<BufferedImage> listImg = splitImage(img);  
      180.            if (listImg.size() == 4) {  
      181.                for (int j = 0; j < listImg.size(); ++j) {  
      182.                    ImageIO.write(listImg.get(j), "JPG", new File("train2//"  
      183.                            + file.getName().charAt(j) + "-" + (index++)  
      184.                            + ".jpg"));  
      185.                }  
      186.            }  
      187.        }  
      188.    }  
      189.  
      190.    /**  
      191.    * @param args  
      192.    * @throws Exception  
      193.    */  
      194.    public static void main(String[] args) throws Exception {  
      195.        // downloadImage();  
      196.        for (int i = 0; i < 30; ++i) {  
      197.            String text = getAllOcr("img2//" + i + ".jpg");  
      198.            System.out.println(i + ".jpg = " + text);  
      199.        }  
      200.    }  
      201.}  
      像BAT這種巨頭的驗證碼通過干擾線、加粗不加粗混用、采用中文常用字(中文常用字大概有5000個,筆畫繁復,形似字多,比起26個字母難度高很多)、不同的字體混用,比如楷體、宋體、幼圓混用、拼音,扭曲字體、需要準確識別13位漢字,大大增加了失敗概率。

       



       



      當然除了主流的圖片驗證碼外,一些網(wǎng)站為了照顧視力不好的用戶,采用語音驗證碼。一般這種驗證碼是機器生成一段讀數(shù)字的語音。但是在這方面上很多程序員都偷懶了,預先找了10個數(shù)字的聲音錄音,然后生成的時候把他們隨機拼到一起,結(jié)果就是這樣:

       



      設(shè)計原理如下:

      整體效果

      ·字符數(shù)量一定范圍內(nèi)隨機

      ·字體大小一定范圍內(nèi)隨機

      ·波浪扭曲(角度方向一定范圍內(nèi)隨機)

      ·防識別

      ·不要過度依賴防識別技術(shù)

      ·不要使用過多字符集-用戶體驗差

      ·防分割 ·

      重疊粘連比干擾線效果好

      ·備用計劃

      ·同樣強度完全不同的一套驗證碼

      既然原理都已經(jīng)知道了,那么如何破解就變得簡單了。

      但是問題來了,這次12306的驗證碼居然是圖片,以上方式都不能使用,那么就不能破解了么?

      有人認為12306的網(wǎng)站圖片內(nèi)存不會太大,完全可以扒下來,然后進行破解。當然這是紙上談兵,有一種非常先進又非常原始的辦法叫做“網(wǎng)絡(luò)打碼”或者“人肉打碼”

       



      一些技術(shù)大牛把驗證碼發(fā)送的自制的“打碼”軟件上,而一些“打碼工”通過這個程序來輸入機器自動注冊,出來的驗證碼,傳輸?shù)阶詣幼詸C器,完成驗證。

      目前來看這種簡單粗暴的方法可以應對目前的情況。

      結(jié)語:

      12306這次可謂出了殺招,把所有搶票軟件一刀砍死,黃牛們不開心我們就可以買到票了。既解決了黃牛問題又為廣大程序員出了一道難題。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約