美文网首页产品撸技术PHP开发程序员
后端开发:APP与后端交互的安全性

后端开发:APP与后端交互的安全性

作者: 赵晓天 | 来源:发表于2017-07-15 12:35 被阅读2815次
    声明

    此文原创,未经允许,禁止转载,可以分享。

    最近在做一个项目,是一个APP的后端开发。我需要完成后端框架的建立、数据库设计、后端代码的编写。在这里讲一下APP与后端交互的安全性。

    没有AUTH的验证

    最简单的验证机制是通过session来存储认证信息的,但这个不便于客户端存储,而且有不能跨域请求认证的缺点。

    大致流程:

    • 用户登录(输入账户密码)
    • 后端验证
    • 验证通过则在session存储用户ID

    每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

    Basic 认证方式

    传统的认证方式就是构造一个字符串,这个字符串里面含有账户名和密码,比如:

    $str = "username:password";
    

    如果希望它不可读,可以对其进行base64编码:

    $str = "username:password";
    $token = base64_encode($str);
    echo $token;
    
    dXNlcm5hbWU6cGFzc3dvcmQ=
    

    这样每次请求API的时候加上这个Token值,然后后端获取到这个Token值,对其进行:

    $str = base64_decode($token);
    $auth = explode(':', $str);
    var_dump($auth);
    

    然后使用auth到数据库中进行查询来验证有效性。

    但缺点很明显:

    • 被窃取的可能性:每次使用这个token值进行请求,意味着每次请求都在泄露用户的密码。
    • 增加数据库工作量:每次请求都要去数据库查询是否有效,效率明显下降。

    对于传统的AUTH方式做了改进,引入JWT。

    JWT认证机制
    什么是JWT?

    Json web token (JWT), 是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

    它的核心就是签名。比如我有一个字符串。

    $str = "qq:792598794;name:sungod";
    

    我该怎么验证这是我给的字符串呢?
    方法很简单,对这个字符串和一个密钥,一起进行不可逆运算

    echo md5($str . 'KEY');
    echo sha1($str . 'KEY');
    echo crypt($str, 'KEY');
    

    假如我们使用sha1算法对其进行不可逆运行,得到:

    81a2453b89cb914c2208a37e3ca4e4f26c44fe43
    

    然后我们将这个结果放入到$str

    $str = "qq:792598794;name:sungod;auth=81a2453b89cb914c2208a37e3ca4e4f26c44fe43";
    echo base64_encode($str);
    
    cXE6NzkyNTk4Nzk0O25hbWU6c3VuZ29kO2F1dGg9ODFhMjQ1M2I4OWNiOTE0YzIyMDhhMzdlM2NhNGU0ZjI2YzQ0ZmU0Mw==
    

    这样,如果KEY只有我知道(前提是肯定只有我知道),那么我敢说这个字符串一定是我给的。

    利用这个,我们前人总结出了一个规范JWT。

    JWT流程
    • 客户端使用账户密码进行签名请求
    • 服务器验证账户密码是否有效
    • 通过验证服务器返回一个Token
    • 客户端存储这个Token,并每次请求都携带
    • 服务器接收到需要验证的请求,验证客户端发来的Token

    这个Token可以放在请求头、Cookie、GET、POST,看具体的业务逻辑需要。

    如何正确的构造JWT

    在PHP中,我们需要一个数组,这个数组用来存储用户的主要信息

    $data = [
            'uid'      =>  10000,
            'exp'      =>  time() + 3600,
        ];
    

    uid 表示用户的ID,键值尽量不要取得太长uid三个字符刚好。
    exp 表示这个Token什么时候失效,这里是当前时间的1小时后。

    对于一个数组,我们不能把它进行不可逆运行,需要将其转换一下。

    // 转换为json字符串
    $data = json_encode($data);
    // 转换为base64编码
    $data = base64_encode($data);
    echo $data;
    

    最后我们数组成为了一个字符串,每次都不一样,因为有时间在变化

    eyJ1aWQiOjEwMDAwLCJleHAiOjE1MDI2ODQ3MjF9
    

    我们这这个字符串与KEY进行不可逆运行(签名),使用PHP自带的函数,它可以很友好的将我们的 data 进行不可逆运行,有关sha1

    $auth = sha1($data . "KEY");
    echo $auth;
    

    得到的签名

    eb96a0b2df742f89192f40191122845b32fc7d01
    

    将其和经过base64转换的数组信息进行拼接

    eyJ1aWQiOjEwMDAwLCJleHAiOjE1MDI2ODQ3MjF9:eb96a0b2df742f89192f40191122845b32fc7d01
    

    最后将其base64编码

    ZXlKMWFXUWlPakV3TURBd0xDSmxlSEFpT2pFMU1ESTJPRFEzTWpGOTplYjk2YTBiMmRmNzQyZjg5MTkyZjQwMTkxMTIyODQ1YjMyZmM3ZDAx
    

    这样我们就可以使用此字符串作为Token来和后端进行交互了。

    注意

    data数组中不能存放敏感的信息,因为传统的base64编码是可以在客户端解开的。

    在此,我们可以自定义一个base64编码,加一个key来进行base64。

    下面利用base64修改的一个对称加密方案:

    // 自定义Base64编码
    function my_base64_encode($data, $key) {
        $str_arr = str_split(base64_encode($data));
        $str_count = count($str_arr);
        foreach (str_split($key) as $key => $value) {
            $key < $str_count && $str_arr[$key] .= $value;
        }
        return join('', $str_arr);
    }
    
    // 自定义Base64解码
    function my_base64_decode($data, $key) {
        $str_arr = str_split($data, 2);
        $str_count = count($str_arr);
        foreach (str_split($key) as $key => $value) {
            $key <= $str_count  && isset($str_arr[$key]) && $str_arr[$key][1] === $value && $str_arr[$key] = $str_arr[$key][0];
        }
        return base64_decode(join('', $str_arr));
    }
    

    使用相同的key进行对称加密,即使别人获取到了Token,也不清楚里面的构造,利用时间换了安全性。

    我们利用my_base64_encode对Token进行加密

    eyJ1aWQiOjEwMDAwLCJleHAiOjE1MDI2ODQ3MjF9:eb96a0b2df742f89192f40191122845b32fc7d01
    

    得到:

    ZtXolkKeMnW_FsXaUlWtlPakV3TURBd0xDSmxlSEFpT2pFMU1ESTJPRFEzTWpGOTplYjk2YTBiMmRmNzQyZjg5MTkyZjQwMTkxMTIyODQ1YjMyZmM3ZDAxCg==
    

    好了!

    这是我做后端学到的知识,我认为还是不错的,分享给大家!
    写的有不好,或者有问题的地方,欢迎更正!!

    相关文章

      网友评论

      • 9ce348ea60c0:Token怎么放在请求头?
      • 敲代码的麦兜:请问jwt生成的token是否需要存储,如果不需要那么验证token的方式是按照之前加密的方式解密后验证uid和传过来的uid是否一致?token失效之后,是当前接口再返回一个token还是让客户端重新去签名?
        赵晓天:@敲代码的麦兜 生成的token有多种存储方式,可以存在cookie中,也可以存在app本地,token失效后最好提示客户端重新登录申请token。也可以在用户每次打开app时申请token。
      • __夏至未至:学习了,不过貌似走SSL还是可以被抓包的啊?
        赵晓天:@__夏至未至 那个情况的话,就不属于中间人了,是用户自己要去查看自己的信息。
        __夏至未至:@赵晓天 可是用青花瓷也可以抓到HTTPS的包啊。HTTPS也会走SSL通道的额。
        赵晓天:@__夏至未至 SSL是非对称建立连接,对称加密数据,所以说,中间人获取的都是加密后的数据。
      • ankyliu:只要截取这段完整验证码就能伪造他人身份?
        ankyliu: @赵晓天 是个好办法,但部署门槛就高了。
        赵晓天:@ankyliu 理论上是这样,采用ssl可保证第三方人员无法抓包
      • 地板砖:学习了

      本文标题:后端开发:APP与后端交互的安全性

      本文链接:https://www.haomeiwen.com/subject/ttmahxtx.html