zoukankan      html  css  js  c++  java
  • 破解另一家网站的反爬机制 & HMAC 算法

    零、写在前面


    本文涉及的反爬技术,仅供个人技术学习,禁止并做到:

    • 干扰被访问网站的正常运行
    • 抓取受到法律保护的特定类型的数据或信息
    • 搜集到的数据禁止传播、交给第三方使用、或者牟利
    • 如有可能,在爬到数据后24小时候内删除

    具体可参考 2019年5月28号 颁布的 《数据安全管理办法(征求意见稿)》

    一、背景


    今天在爬另一家网站数据时,想直接从 ajax 接口入手,但是发现这些 request 加了额外参数来防止爬取,即在 request header 里,有一对随机key-value 参数:形如 e931588bc0dfbc5e6323 : c43dfe7cdc49b6318f43907ad4e7d9b69a23719d2e3b7b59799124408aa11cf383f459a4a558af8c64b289b7d974982aad58db705ac6784460733bd21784bde0,故意让你猜不到。

    但是操作了一会,我总结了如下规律:

    1、每个不同的接口 url,对应不同的 key ,但这个 key 刷新页面是不会变得。(看来 key 跟 url 有关)

    2、每个 key 对应的 value 一直在变。(事后才知道 value 是根据 url 和 post body 共同决定的)

    二、破解


    于是通过网站被混淆过的 js ,耐心的打断点分析。

    过程略。

    三、结果


    最后发现:

    key 和 value 都是通过 HMAC(Keyed-Hashing for Message Authentication) 算法得来的。

    1、HMAC 算法

    HMAC 其实就等于我们平常用的 MD5 / SHA-1 去加 salt 的操作。而采用 HMAC 的好处就是,替代我们自己的 salt 算法,使得程序算法更标准化,也更安全

    HMAC 可选择搭配 MD5 / SHA-1 或等等。这里用的是 SHA512

    >>> import hmac
    >>> key = b'secret'
    >>> message = b'Hello, world!'
    >>> h = hmac.new(key, message, digestmod='MD5')
    >>> h.hexdigest()
    'fa4ee7d173f2d97ee79022d1a7355bcf'
    

    注意:传入的 key 和 message 都是bytes类型,所以str类型需要首先被编码为bytes

    2、最终代码

    注意:敏感信息被隐藏处理。

    import hashlib
    import hmac
    import requests
    import json
    
    host = 'http://example.com'
    # request's param - 变化值
    uri = '/api/search/example'
    data = {
        "cityName": "上海",
        "cityCode": "31",
        # 等等
    }
    
    # hmac's secret - 固定值
    secret = b'abcdefg'
    
    # calculate key
    sign_key = hmac.new(secret, uri.lower().encode(), hashlib.sha512).hexdigest()
    header_key = sign_key[10:30]  
    
    # calculate value
    sign_value = (uri.lower()+uri.lower() +
                  json.dumps(data, separators=(',', ':'), ensure_ascii=False)).lower()
    header_value = hmac.new(secret, sign_value.encode(),
                            hashlib.sha512).hexdigest()
    # print result
    print(header_key, header_value)
    
    

    然后我们把算出来的 key 和 value 塞入到每一次请求的 header 里,即可成功调用。

    3、坑

    上面代码在算 value 的时候,用了 json.dumps(),把中文 上海 转为了 "u4e0au6d77",而不是上海,导致接口一直报错。

    解决办法:json.dumps 多传一个参数 ensure_ascii=False

  • 相关阅读:
    Mego(02)
    Mego(01)
    ThoughtWorks(中国)程序员读书雷达 —— 书籍下载整理
    Spring源码编译一次性通过&遇到的坑解决方法
    Elasticsearch怎么修改索引字段类型?
    Flume 自定义拦截器 多行读取日志+截断
    用Hibernate框架把hql生成可执行的sql语句-Oracle方言
    深入浅出SQL Server中的死锁 [转于CareySon]
    第一次迭代随笔
    结对编程代码分析
  • 原文地址:https://www.cnblogs.com/xjnotxj/p/11934756.html
Copyright © 2011-2022 走看看