Python中的CSRF攻击与JSON Web Token验证

2023-04-17 00:00:00 csrf 验证 攻击

CSRF攻击(Cross-Site Request Forgery,跨站请求伪造)指的是攻击者在用户不知情的情况下,通过第三方站点向目标站点发送恶意请求,例如转账、更改密码等操作。为了避免这种攻击,通常会在表单中添加一个随机生成的token,而在提交表单时,只有当该token与服务器记录的token一致时,才会被服务器接受。

Python中可以使用Django框架提供的装饰器来自动添加token,使用方法如下:

from django.views.decorators.csrf import csrf_protect, csrf_exempt

@csrf_protect # 添加CSRF token保护
def my_view(request):
    ...

@csrf_exempt # 不添加CSRF token保护
def my_other_view(request):
    ...

其中,csrf_protect() 装饰器会自动在表单中添加token,而 csrf_exempt() 则会禁用该保护措施。

而在使用Ajax发送请求时,需要在请求头中添加 X-CSRFToken 字段,其值为当前页面的token。可以使用以下代码来获取token和发送POST请求:

// 获取token的值
var csrftoken = getCookie('csrftoken');

// 发送POST请求
$.ajax({
    type: 'POST',
    url: '/my_url/',
    data: { name: 'pidancode.com', content: 'Hello, 皮蛋编程!' },
    beforeSend: function(xhr, settings) {
        xhr.setRequestHeader("X-CSRFToken", csrftoken);
    },
    success: function(result) {
        console.log(result);
    }
});

// 获取cookie中的值
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = $.trim(cookies[i]);
            // 在cookie中查找token
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

JSON Web Token(JWT)是一种用于身份验证的开放标准(RFC 7519),其使用JSON格式对信息进行编码,并约定由三部分组成:头部、载荷和签名。JWT的格式如下:

header.payload.signature

其中,头部用于指定加密算法等信息,载荷用于存储实际的信息,例如用户ID、权限等,而签名用于验证数据的完整性和真实性。

使用JWT验证步骤如下:

  1. 用户在登录时使用用户名和密码向服务器发送请求;
  2. 服务器验证用户名和密码是否匹配,如果匹配则生成一个JWT并返回给客户端;
  3. 客户端在以后每次向服务器发送请求时,在请求头中添加JWT;
  4. 服务器对JWT进行验证,验证成功则允许访问,否则拒绝访问。

Python中可以使用PyJWT包来生成、解析JWT,在安装PyJWT包后,可以使用以下代码生成一个JWT:

import jwt
import datetime

key = "my_secret_key" # 密钥,可以任意指定
payload = {
    'user_id': 123,
    'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30) # 有效期为30分钟
}
token = jwt.encode(payload, key, algorithm='HS256')

在此代码中,jwt.encode() 函数用于生成JWT,其中 payload 参数为需要存储的信息,key 为密钥,用于签名,algorithm 为加密算法,常用的有HS256、RS256等。

在客户端收到JWT后,可以将其存储在cookie或localStorage中,以便以后使用。使用以下代码将JWT解析:

import jwt

key = "my_secret_key" # 密钥必须与生成token时一致
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsImV4cCI6MTYyMDA1MDY5NX0.APEeMR21jK5EnaSG5Z5TIAGnbctNnNWszL61zvbdgEU"

payload = jwt.decode(token, key, algorithms=['HS256'])
print(payload) # {'user_id': 123, 'exp': 1620050695}

在此代码中,jwt.decode() 函数用于解析JWT,其中 token 参数为待解析的JWT,key 为密钥,用于验证签名,algorithms 为加密算法。

因为JWT使用了Base64编码,所以 JWT不能存储敏感信息,不应该存储密码等机密信息。在使用JWT时,应该注意安全性问题。

相关文章