来源:http://meiyitianabc.blog.163.com/blog/static/10502212720131056273619/

我认为,保护服务器端的数据,有这么几个关键点:

  1. 不能对使用体验产生影响,这就排除掉了诸如每次接口调用都要求用户输入验证码这样的做法
  2. 接口调用的网络交互需要无规律可循,比如article/1 –> article/1000 这样的接口就太容易被其他人爬走了
  3. 要严格意义上阻击爬虫,需要每一次网络请求都是不可重放的,这样才能避免其他人通过监听网络交互并重放来爬取数据
  4. 对服务器端编码不产生太大影响,如果要对服务器端伤筋动骨的大改,肯定是要不得的

通常,我们会采用一种简单有效的方法:对服务器返回的数据加密来解决,但是,这种做法并没有解决上面所提到的第二点,接口调用的时候url的规律性太强,网络监听一下数据,就很容易找到url地址的规律了,加密的破解也很简单,反编译直接定位到解密函数,拿到密钥。当然,在强大的反编译工程面前,一切努力都是徒劳的,不管你用何种方法,都是可以把中间的逻辑找到并模拟成一个客户端来爬数据的。

我下面就提出一个破解更加复杂一些的方法,在客户端产生请求时,对接口url进行RSA加密处理。

假设我们本来需要访问 http://api.example.com/articles 这样的一个接口,接口返回json数据。在客户端访问之前,我们先对这个url进行这样的处理:

  1. 加客户端时间戳:http://api.example.com/1322470148/articles
  2. 对url的path段进行rsa加密,然后base64:http://api.example.com/TBhIskCgCN+WMK3PftbYzPQFAKvx9sE9OMOxvL00kCBlNiKw2C1Mb7oGcfUepTxauG06NLBNhr5BFtjt7Xu7uwdpUYyVcFRdI37SVyGRCOzaxACOGXGpX5dHZqQJia0icxwWJ+D1RiJqxFWQ++3/IgUOgDzgvQnPIl420bpztB8=

我们真实访问的地址就变成了这样一个长长的 url 结构,我们通过rsa算法的padding参数和时间戳,就可以让这个后面长长的bas64串在每次访问的时候都发生变化,同时,我们可以在服务器端把一个小时之内的请求过的串都记下来,并不让再次访问,这样就防止了爬虫的重放请求尝试。

在服务器端,我们就需要在做响应之前,把url还原回来。在服务器端,现在都是框架的天下,一般都有唯一的入口,如果使用的是php语言,主要在入口的index.php加上一些代码就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if ($_SERVER['HTTP_HOST'] == "api.example.com"){ // 只针对api这个域名做处理
    include_once dirname(__FILE__).'/protected/components/EncryptUtil.php'; // 加解密库,你需要实现你自己的加解密类
    $request_uri = $_SERVER['REQUEST_URI'];
    if(isset($_SERVER['HTTP_HOST'])){
        if(strpos($request_uri,$_SERVER['HTTP_HOST'])!==false){
            // 把 REQUEST_URI 中可能包含的host信息去除掉
            $request_uri=preg_replace('/^\w+:\/\/[^\/]+/','',$request_uri);
        }
    }
    $encoded = base64_decode(substr($request_uri, 1));
    if($encoded && strlen($encoded) % 128 ===0){
        $real_uri = EncryptUtil::private_decrypt($encoded);         // 解密url路径
        if(!$real_uri){ echo ":)"; return; }                        // 解密失败
        if(preg_match("/([0-9]+)\\/(.+)/", $real_uri, $matches)){   // 提取出时间戳和真实的url请求地址
            $timestamp = $matches[1];                               // 客户端请求的时间戳
            $real_uri = $matches[2];                                // 客户端请求的真实地址
            $_SERVER['REQUEST_URI'] = $real_uri;                    // 置上本来应该有的全局$_SERVER['REQUEST_URI']
            if(preg_match("/^[^?]+\\?(.+)/", $real_uri, $matches)){
                $_SERVER['QUERY_STRING'] = $matches[1];             // 置上本来应该有的全局$_SERVER['QUERY_STRING']
                parse_str($_SERVER['QUERY_STRING'], $array);
                $_REQUEST = array_merge($_REQUEST, $array);         // 置上本来应该被设置的全局$_REQUEST
                $_GET = array_merge($_GET, $array);                 // 置上本来应该被设置的全局$_GET
            }
        }else{ // url的格式不符合,没有包含时间戳
            echo ":)"; return;
        }
    }else{ // url的长度不符合规则
        echo ":)"; return;
    }
}

在经过这样一段代码处理之后,框架就一切正常,其他代码都不需要做变更,就有了rsa加密的url支持,当然,这几行代码还是不能阻止重放攻击的,里面并没有对请求过的url进行记录处理,要实现url访问的唯一性,还需要额外的更多代码。

服务器端完成了,那客户端也同样需要做相应操作,我这里就不详细讲解了,贴上一段修改过的实际运行的代码,IOS,应用了 three20库,并兼容TTURLRequest缓存机制。

 

Android的Java版本我就把实际运行中的代码的http部分抽离出来,因为牵涉到一些相关配置,代码不能正常编译,不过也放在这里,以供参考。

android-rsa-http.zip下载地址

用法示例:

1
2
3
BaiyiApiRequest request = new BaiyiApiRequest("articles/1");
request.setListener(this);
request.start();

http接口加密《一》:移动应用中,通过在客户端对访问的url进行加密处理来保护服务器上的数据的更多相关文章

  1. 客户端挂载NFS服务器中的共享目录(用户后台上传图片与前台上传图片放在同一个服务器上)

    服务器端使用showmount命令查询NFS的共享状态 # showmount -e //默认查看自己共享的服务,前提是要DNS能解析自己,不然容易报错 # showmount -a //显示已经与客 ...

  2. api 接口开发理论 在php中调用接口以及编写接口

    如: http://localhost/openUser.php?act=get_user_list&type=json 在这里openUser.php相当于一个接口,其中get_user_l ...

  3. 在IOS中使用DES算法对Sqlite数据库进行内容加密存储并读取解密

    在IOS中使用DES算法对Sqlite 数据库进行内容加密存储并读取解密 涉及知识点: 1.DES加密算法: 2.OC对Sqlite数据库的读写: 3.IOS APP文件存储的两种方式及读取方式. 以 ...

  4. 类与接口(三)java中的接口与嵌套接口

    一.接口 1. 接口简介 接口: 是java的一种抽象类型,是抽象方法的集合.接口比抽象类更加抽象的抽象类型. 接口语法: [修饰符] [abstract] interface 接口名 [extend ...

  5. 基于接口回调详解JUC中Callable和FutureTask实现原理

    Callable接口和FutureTask实现类,是JUC(Java Util Concurrent)包中很重要的两个技术实现,它们使获取多线程运行结果成为可能.它们底层的实现,就是基于接口回调技术. ...

  6. 腾讯微博API时间线相关接口返回的微博信息中head值使用问题

    腾讯微博API时间线相关接口返回的微博信息中head值表示作者头像url,这个链接直接访问并不能使用,需要再附加一个参数指定图片的大小(100.50),比如:[head]/100.

  7. spice在桌面虚拟化中的应用系列之三(USB映射实现,SSL加密,密码认证,多客户端支持)

    本系列其它文章 spice在桌面虚拟化中的应用系列之一(spice简介,性能优化等) spice在桌面虚拟化中的应用系列之二(Linux平台spice客户端的编译安装,支持USB映射) 1.spice ...

  8. Windows中的权限设置、文件压缩、文件加密、磁盘配额和卷影副本

      目录 权限设置 文件夹的NTFS权限 文件的NTFS权限 NTFS权限的应用规则 文件压缩 文件加密 磁盘配额 卷影副本 权限设置的应用 遇到的一个权限问题的小bug 权限问题的实际应用 权限设置 ...

  9. 常用的函数式接口_Supplier和常用的函数式接口Supplier接口练习_求数组中元素最大值

    Supplier接口 package com.yang.Test.SupplierStudy; import java.util.function.Supplier; /** * 常用的函数式接口 * ...

随机推荐

  1. ubuntu 笔记

    Ubuntu学习之路还很长,做个笔记也不亏 terminal tab 补全忽略大小写: 在 /ect/inputrc文件中添加或修改 'set completion-ignore-case on' U ...

  2. javascript 随机显示指定内容

    今天碰到一个需求,一个页面显示赞助厂商的信息,但是厂商要求排序要随机排,因为是个静态页面不是读取数据库的,所以打算用js来控制 var arr = new Array('张三', '李四', '王五' ...

  3. 《Django By Example》第十章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译本章过程中几次想放弃,但是既然 ...

  4. iOS开发之数据存储之Preference(偏好设置)

    1.概述 很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能. 每个应用都有个NSUserDefaults实例,通过它来存取偏好 ...

  5. 什么是https

    我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议. HTTPS简介 HTTPS其实是有两部分组成:HTTP + SSL ...

  6. c++学习笔记之封装篇(上)

    title: c++学习笔记之封装篇(上) date: 2017-03-12 18:59:01 tags: [c++,c,封装,类] categories: [学习,程序员,c/c++] --- 一. ...

  7. Jenkins集成Docker

    大概过程如下图: 由于需要用到docker打包镜像,jenkins宿主机上需要安装docker,原先的jenkins server安装在centos6上无法运行docker,所以这里单独用一台cent ...

  8. Apache Mina入门实例

    一.mina是啥 ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的 ...

  9. CF #401 (Div. 2) C.Alyona and Spreadsheet (思维)

    题意:给你n行m列的数组,和k次的询问,问从l行到r行是否存在一个非递增的列 思路:看到这道题的数据量我们就知道直接暴力不可取,所以我们采用了预处理的方法,我们记录下来每一行的最长的非递减的列的开头的 ...

  10. 线上分享会.net框架“ABP”分享会总结

    前言 为了能够帮助.Net开发者开拓视野,更好的把最新的技术应用到工作中,我在3月底受邀到如鹏网.net训练营直播间为各位学弟学妹们进行ABP框架的直播分享.同时为了让更多的.NET开发者了解ABP框 ...