跨域post 及 使用token防止csrf 攻击_通过token解决cors安全性问题-程序员宅基地

技术标签: angular  python  安全  csrf  flask  跨域post  

环境:
后台使用的python - flask
前台使用angular框架

1.一个跨域post的例子:

跨域post有多种实现方式:

1.CORS:http://blog.csdn.net/hfahe/article/details/7730944
2.利用iframe
3.server proxy:https://en.wikipedia.org/wiki/Proxy_server

例子使用的为iframe,想要证明,在没有进行csrf防御时,任意攻击者可以利用javascript发送 post 请求,从而简单的提交或获取数据资料;

1.本地test.html页面

<html>
<head>
<title>POST</title>
<script type="text/javascript" src="jquery-2.1.4.min.js"></script>
</head>
<body>
<input type="button" onclick="test();" value="test"/>
<script type="text/javascript">
    function test() {
     
        crossDomainPost({
            url: 'http://localhost:5000/test',
            param: {a: '1', b: '2'},
            onSubmit: function (e) {
     
                console.log(e);
            }
        })
    }
    function crossDomainPost(config) {
     
        var def = {
            url         : '',                   //提交的地址
            param       : {},                   //提交的参数
            delay       : 1000,                 //延迟获取参数的时间,单位为毫秒
            onSubmit    : function (i) {
     }       //提交成功后的回调函数,参数为跳转的IFRAME
        };
        config  = $.extend({}, def, config);
        if (!config.url) {
            config.onSubmit({error: 'URL is Empty!'});
            return;
        }
        /****baseMethod****/
        /**
         * 生成随机的10位字符,且唯一
         * @returns {string}
         */
        var createGuid    = function () {
     
            var guid = "";
            for (var i = 1; i <= 10; i++) {
                guid += Math.floor(Math.random() * 16.0).toString(16);
            }
            return guid;
        },
        /**
         * 删除指定的节点
         * @param _element 要删除的节点
         */
        removeElement = function (_element) {
     
            var _parentElement = _element.parentNode;
            if (_parentElement) {
                _parentElement.removeChild(_element);
            }
        }

        // Add the iframe with a unique name
        var iframe                = document.createElement("iframe");
        var uniqueString          = createGuid();
        document.body.appendChild(iframe);
        iframe.style.display      = "none";
        iframe.contentWindow.name = uniqueString;

        // construct a form with hidden inputs, targeting the iframe
        var form    = document.createElement("form");
        form.target = uniqueString;
        form.action = config.url;
        form.method = "POST";

        // repeat for each parameter
        for (var item in config.param) {
            var input   = document.createElement("input");
            input.type  = "hidden";
            input.name  = item;
            input.value = config.param[ item ];
            form.appendChild(input);
        }

        document.body.appendChild(form);
        try{
            form.submit();
        }catch(e){
            console.log('error');
            consoel.log(e);
        }


        setTimeout(function () {
     
            config.onSubmit(iframe);
            removeElement(form);    //移除form
        }, config.delay);
    }
    </script>
</body>
</html>

2.后台接收代码

这里仅接收POST的请求

@app.route('/test' ,methods=['POST'])
def test():
    print 'param is :';
    print request.form
    return jsonify(data='2222')

3.控制台输出:

服务端处理了非站内的请求

这里写图片描述

4.浏览器输出:

本地test.html获取到返回信息

这里写图片描述


2.CSRF

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。

1.原理

这里写图片描述

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  • 登录受信任网站A,并在本地生成Cookie。
  • 在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

原理详细:http://www.80sec.com/csrf-securit.html

2.常见的攻击类型:

1.GET类型的CSRF
只需要一个HTTP请求,就可以构造一次简单的CSRF。
例子:
银行网站A:它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000
危险网站B:它里面有一段HTML的代码如下:

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块

为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源http://www.mybank.com/Transfer.php?toBankId=11&money=1000 ,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作

2.POST类型的CSRF
如上边的跨域POST例子

3.如何防御CSRF

1.提交验证码
在表单中增加一个随机的数字或字母验证码,通过强制用户和应用进行交互,来有效地遏制CSRF攻击。

2.Referer Check
检查如果是非正常页面过来的请求,则极有可能是CSRF攻击。

3.token验证

  • 在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有
    token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
  • token需要足够随机
  • 敏感的操作应该使用POST,而不是GET,以form表单的形式提交,可以避免token泄露。

4.在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。


4.关于token

  1. Token 应该被保存起来(放到 local / session stograge 或者 cookies
  2. Tokens 除了像 cookie 一样有有效期,而且你可以有更多的操作方法。一旦 token 过期,只需要重新获取一个。你可以使用一个接口去刷新 token;你甚至可以把 token 原来的发布时间也保存起来,并且强制在两星期后重新登录什么的;如果你需要撤回 tokens(当 token 的生存期比较长的时候这很有必要)那么你需要一个 token 的生成管理器去作检查。
  3. Local / session storage 不会跨域工作,请使用一个标记 cookie
  4. 有需要的话,要加密并且签名 token
  5. 将 JSON Web Tokens 应用到 OAuth 2

使用Token

1.引入csrf

from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()

app = Flask(__name__)

csrf.init_app(app)
app.config['SECRET_KEY']='myblog'

2.在站内页面上head中,增加token

<meta name="csrf-token" content="{
    { csrf_token() }}">

3.配置angular提交表头

app.config(function ($httpProvider) {
    
    $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
});

4.再次测试跨域post
后台输出:
这里写图片描述
前台输出:
这里写图片描述


关于webapp跨域Post使用token思路:

  1. 移动端登录时,服务端验证表单信息,登陆成功,生成token,返回给客户端;
  2. 客户端将token存在localstorage/sessionstorage中,每次提交表单,都需要携带token;
  3. 服务端获取请求,如果没有token,则忽略请求;

出现的问题:

  1. 服务端需要限制登陆次数
    解决方法:
    客户端增加登陆间隔,请求一次后,等待x秒才能再次请求
    服务端做cas验证

  2. 服务端需要保存用户的token,及过期时间;
    解决方法:
    可以将token 保存在Memcache,数据库中,redis

  3. 客户端存token时,需要对token加密
    解决方法:
    在存储的时候把token进行对称加密存储,用时解开
    将请求URL、时间戳、token三者进行合并加盐签名,服务端校验有效性

当然,以上只防君子,不防小人

参考:
跨域post请求:http://blog.csdn.net/doraeimo/article/details/7329779
跨站请求伪造:http://www.jianshu.com/p/7f33f9c7997b
token:http://alvinzhu.me/blog/2014/08/26/10-things-you-should-know-about-tokens/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013934914/article/details/50428869

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签