title: “down-csrf-token改造记录” date: 2024-03-26 hiddenFromHomePage: true hiddenFromSearch: true categories:

  • 网站开发 tags:
  • token
  • csrf keywords:
  • token
  • csrf url: “/goals/web-add-csrf-token”

前端代码:

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
【<head>
<script>
async function getCsrfToken() {
    const response = await fetch('/get_csrf_token');
    if (!response.ok) {
        throw new Error('Failed to fetch CSRF token');
    }
    const { csrf_token } = await response.json();
    return csrf_token;
}

window.addEventListener('DOMContentLoaded', async () => {
    const csrfToken = await getCsrfToken();
    document.querySelector('input[name="my_csrf_token"]').value = csrfToken;
});
</script>
.....
</head>
.....
<div id="container" class="mdui-card mdui-center">
<form id="form_url"   >
  <label for="video_link"> </label>
  <input type="text" id="video_link" name="video_link" onfocus="this.value=''"  value="请输入视频页面url 比如: https://v.test.com/UGQaf5o/" style="color: gray;">
  <input type="hidden" name="my_csrf_token" value="">
  <button id="download_btn" type="submit">Download</button>
  <p id="error_message" style="display:none">Uh-Oh! 可能是没有,请更换url</p>
</form>
</div>
.....
<script>
document.getElementById("download_btn").addEventListener("click", async function() {
    event.preventDefault(); // 阻止表单默认提交行为
    document.getElementById("download_btn").innerText = "Downloading...";
    document.getElementById("download_btn").setAttribute("disabled", "disabled");

    const v = document.getElementById('video_link').value;
    let regex;
	if (v.includes("test")) {
	  regex = /http[s]?:\/\/[\w.]+[\w\/]*[\w.]*\??[\w=&:\-\+\%]*[/]*/;
	} else if (v.includes("test")) {
	   regex = /http[s]?:\/\/[\w.]+\/@[\w.-]+\/video\/\d+/;
    }
    const video_link = v.match(regex)[0];

    const csrftoken = document.querySelector('input[name="my_csrf_token"]').value;
    const formData = new FormData();
    formData.append('video_link', video_link);
    formData.append('my_csrf_token', csrftoken); // 将csrf_token作为表单数据发送

    try {
        const response = await fetch('/download', {
            method: 'POST',
            body: formData
        });

        if (!response.ok) {
            document.getElementById("error_message").style.display = "block";
            download_btn.innerText = "Download";
            download_btn.removeAttribute("disabled");
            return;
        }

        const jsonData = await response.json();

        // Remove  form_url 
        document.getElementById("form_url").style.display = "none";

        // create and add the thumbnail image
        const thumb = document.createElement("img");
        const imageDiv = document.createElement("div");
        thumb.src = jsonData.thumb;
        thumb.classList.add("thumb-img");
        imageDiv.classList.add("mdui-card-media");
        imageDiv.appendChild(thumb);
		.....
</script>】

后端代码:

 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
31
32
33
34
35
36
37
38
from flask import Flask, request, jsonify, render_template_string
import requests
import json
import qrcode
from fake_useragent import UserAgent
from subprocess import run, PIPE

from flask_wtf.csrf import CSRFProtect, generate_csrf, CSRFError
from werkzeug.exceptions import BadRequest

app = Flask(__name__)

app.config['SECRET_KEY'] = '3D6SWx9deteds1'  #随机密钥
csrf = CSRFProtect(app)  # 初始化CsrfProtect

@app.errorhandler(CSRFError)
def handle_csrf_error(e):
    return jsonify({"error": e.description}), 400

@app.route('/get_csrf_token', methods=['GET'])
def get_csrf_token():
    return jsonify({'csrf_token': generate_csrf()})
    
#################################download start #################################
# 移除豁免装饰器 @csrf.exempt  #如果不删除这个  400报错  Missing CSRF token
@app.route("/download", methods=["POST"])
def download():
    csrf_token = request.form.get('my_csrf_token')  # 假设CSRF令牌通过表单字段发送
    if not csrf_token:
        return jsonify({"error": "Missing CSRF token"}), 400
        
    
    video_link = request.form.get("video_link")  # 从表单数据中获取video_link
    if not video_link:
        return jsonify({"error": "Video link is required"}), 400
	.....	

csrf版本: /home/wwwroot/down/douyin/en/indexnot-csrf.html /usr/src/TwitterMedia/x103_youtube_dy_tiktok-backend-csrf.py

https://v.2urs.com/douyin/en/index-csrf.html ok
非csrf版本: /home/wwwroot/down/douyin/en/index.html /usr/src/TwitterMedia/x103_youtube_dy_tiktok-backend.py

https://v.2urs.com/douyin/en/index.html ok csrf-token 版本: /home/wwwroot/down/douyin/en/index-csrf-token.html /usr/src/x103Media/twitter_youtube_dy_tiktok-backend-csrf-token.py

https://v.2urs.com/douyin/en/index-csrf-token.html?token=uuic-qackd-fga-tdfd ok

https://analyse.layzz.cn/lyz/getAnalyse?token=uuic-qackd-fga-test

https://v.2urs.com/download https://v.douyin.com/iY4jtHC3/


怎样在下面给你的前后端代码的基础上 实现 https://analyse.layzz.cn/lyz/getAnalyse?token=uuic-qackd-fga-test 这个的功能呢。 比如 https://v.test.com/download?token=uuic-qackd-fga-test 如果请求后 次数不足返回 { “code”: “0002”, “method”: null, “message”: “您的次数不足 请联系作者微信 123456” } 假如请求成功。 返回之前的json 。可以使用的总次数减1. 你可以假定 uuic-qackd-fga-test 的信息暂时保存在txt文件中或者字典里面 。格式为: 假如存入字典 1 100 1 ] 1级【token种类 1为测试 2为正式】 100【为使用的次数】 1【1为可用 0为不可用】 前端代码:

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
【<head>
<script>
async function getCsrfToken() {
    const response = await fetch('/get_csrf_token');
    if (!response.ok) {
        throw new Error('Failed to fetch CSRF token');
    }
    const { csrf_token } = await response.json();
    return csrf_token;
}

window.addEventListener('DOMContentLoaded', async () => {
    const csrfToken = await getCsrfToken();
    document.querySelector('input[name="my_csrf_token"]').value = csrfToken;
});
</script>
.....
</head>
.....
<div id="container" class="mdui-card mdui-center">
<form id="form_url"   >
  <label for="video_link"> </label>
  <input type="text" id="video_link" name="video_link" onfocus="this.value=''"  value="请输入视频页面url 比如: https://v.test.com/UGQaf5o/" style="color: gray;">
  <input type="hidden" name="my_csrf_token" value="">
  <button id="download_btn" type="submit">Download</button>
  <p id="error_message" style="display:none">Uh-Oh! 可能是没有,请更换url</p>
</form>
</div>
.....
<script>
document.getElementById("download_btn").addEventListener("click", async function() {
    event.preventDefault(); // 阻止表单默认提交行为
    document.getElementById("download_btn").innerText = "Downloading...";
    document.getElementById("download_btn").setAttribute("disabled", "disabled");

    const v = document.getElementById('video_link').value;
    let regex;
	if (v.includes("test")) {
	  regex = /http[s]?:\/\/[\w.]+[\w\/]*[\w.]*\??[\w=&:\-\+\%]*[/]*/;
	} else if (v.includes("test")) {
	   regex = /http[s]?:\/\/[\w.]+\/@[\w.-]+\/video\/\d+/;
    }
    const video_link = v.match(regex)[0];

    const csrftoken = document.querySelector('input[name="my_csrf_token"]').value;
    const formData = new FormData();
    formData.append('video_link', video_link);
    formData.append('my_csrf_token', csrftoken); // 将csrf_token作为表单数据发送

    try {
        const response = await fetch('/download', {
            method: 'POST',
            body: formData
        });

        if (!response.ok) {
            document.getElementById("error_message").style.display = "block";
            download_btn.innerText = "Download";
            download_btn.removeAttribute("disabled");
            return;
        }

        const jsonData = await response.json();

        // Remove  form_url 
        document.getElementById("form_url").style.display = "none";

        // create and add the thumbnail image
        const thumb = document.createElement("img");
        const imageDiv = document.createElement("div");
        thumb.src = jsonData.thumb;
        thumb.classList.add("thumb-img");
        imageDiv.classList.add("mdui-card-media");
        imageDiv.appendChild(thumb);
		.....
</script>】

后端代码:

 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from flask import Flask, request, jsonify, render_template_string
import requests
import json
import qrcode
from fake_useragent import UserAgent
from subprocess import run, PIPE

from flask_wtf.csrf import CSRFProtect, generate_csrf, CSRFError
from werkzeug.exceptions import BadRequest

app = Flask(__name__)

app.config['SECRET_KEY'] = '3D6SWx9deteds1'  #随机密钥
csrf = CSRFProtect(app)  # 初始化CsrfProtect

@app.errorhandler(CSRFError)
def handle_csrf_error(e):
    return jsonify({"error": e.description}), 400

@app.route('/get_csrf_token', methods=['GET'])
def get_csrf_token():
    return jsonify({'csrf_token': generate_csrf()})
    
#################################download start #################################
# 移除豁免装饰器 @csrf.exempt  #如果不删除这个  400报错  Missing CSRF token
@app.route("/download", methods=["POST"])
def download():
    csrf_token = request.form.get('my_csrf_token')  # 假设CSRF令牌通过表单字段发送
    if not csrf_token:
        return jsonify({"error": "Missing CSRF token"}), 400
        
    
    video_link = request.form.get("video_link")  # 从表单数据中获取video_link
    if not video_link:
        return jsonify({"error": "Video link is required"}), 400
		
	if "x103" in video_link:
        return parse_x103_video(video_link)	
def parse_x103_video(video_link):
    # 使用正则表达式或其他方式解析视频地址        
    video_link = request.json["video_link"]
    url_v2 = "http://127.0.0.1:8010/api/process_v2"
    params = {'video_link': video_link}

    response = requests.get(url_v2, params=params)
    
    if response.status_code == 200:
        return response.json()
    else:
        url_v1 = "http://127.0.0.1:8010/api/process_v1"
        response = requests.get(url_v1, params=params)
        if response.status_code == 200:
            return response.json()
        else:
            return "Error occurred"	
	.....	

请求 en/index-csrf-token.html?token=uuic-qackd-fga-test 还是报错。控制台信息 Token from URL: uuic-qackd-fga-test index-csrf-token.html?token=uuic-qackd-fga-test:297 POST https://v.test.com/download?token=${token} 400 (Bad Request) (匿名) @ index-csrf-token.html?token=uuic-qackd-fga-test:297 就这行 const response = await fetch(’/download?token=${token}’, {

https://v.2urs.com/douyin/en/index-csrf-token.html?token=uuic-qackd-fga-tdfd

ok

使用程序 获取csrf cookie 。 然后构造请求 把csrf cookie 带入 请求。 ok

构造1个bash curl请求 包括 user-agent video_link origin referer

bash

1
2
3
4
  curl 'https://v.2urs.com/download' -H --user-agent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"  -H 'origin: https://v.2urs.com'  -H "Referer: https://v.2urs.com/twitter/" -X GET -H "Content-Type: application/json"     -d '{"video_link": "https://twitter.com/i/status/1580927207987257344"}'  
  
  
    curl 'https://v.2urs.com/download' -H --user-agent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"  -H 'origin: https://v.2urs.com'  -H "Referer: https://v.2urs.com/douyin/en/" -X GET -H "Content-Type: application/json"     -d '{"video_link": "https://v.douyin.com/iY4jtHC3"}' 
---
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
	cmd
	curl "https://v.2urs.com/download" ^
  -H "accept: */*" ^
  -H "accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7" ^
  -H "content-type: application/json" ^
  -H "cookie: _ga=GA1.2.204225576.1709769565; Hm_lvt_b3aa9ed2616f88781f9792c2a0cafa9c=1709515900,1709531436,1709775119,1710211332; _gid=GA1.2.803156679.1713323002; _ga_FYYVZP7K0Z=GS1.2.1713340526.35.0.1713340526.60.0.0" ^
  -H "origin: https://v.2urs.com" ^
  -H "referer: https://v.2urs.com/douyin/en/" ^
  -H ^"sec-ch-ua: ^\^"Microsoft Edge^\^";v=^\^"123^\^", ^\^"Not:A-Brand^\^";v=^\^"8^\^", ^\^"Chromium^\^";v=^\^"123^\^"^" ^
  -H "sec-ch-ua-mobile: ?0" ^
  -H ^"sec-ch-ua-platform: ^\^"Windows^\^"^" ^
  -H "sec-fetch-dest: empty" ^
  -H "sec-fetch-mode: cors" ^
  -H "sec-fetch-site: same-origin" ^
  -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0" ^
  -H ^"x-csrftoken: ^{^{ csrf_token ^}^}^" ^
  --data-raw ^"^{^\^"video_link^\^":^\^"https://v.douyin.com/iY4jtHC3/^\^"^}^"

浏览器 cmd 请求

 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
31
32
33
34
35
curl "https://v.2urs.com/download" ^
-H "accept: */*" ^
-H "accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7" ^
-H "content-type: multipart/form-data; boundary=----WebKitFormBoundaryHTC3EJwKAxoAA7BI" ^
-H "cookie: _ga=GA1.2.204225576.1709769565; Hm_lvt_b3aa9ed2616f88781f9792c2a0cafa9c=1709515900,1709531436,1709775119,1710211332; _gid=GA1.2.803156679.1713323002; _ga_FYYVZP7K0Z=GS1.2.1713340526.35.0.1713340526.60.0.0; session=eyJjc3JmX3Rva2VuIjoiNmExYjU0YTkwZDBkOWE2NzUzMTA4MGRjN2FhMmIwZmIyZjZhYmVmMiJ9.Zh-SlQ.P83h1U1GQsPsSo_OolWs_SiDSCs" ^
-H "origin: https://v.2urs.com" ^
-H "referer: https://v.2urs.com/douyin/en/index-csrf.html" ^
-H ^"sec-ch-ua: ^\^"Microsoft Edge^\^";v=^\^"123^\^", ^\^"Not:A-Brand^\^";v=^\^"8^\^", ^\^"Chromium^\^";v=^\^"123^\^"^" ^
-H "sec-ch-ua-mobile: ?0" ^
-H ^"sec-ch-ua-platform: ^\^"Windows^\^"^" ^
-H "sec-fetch-dest: empty" ^
-H "sec-fetch-mode: cors" ^
-H "sec-fetch-site: same-origin" ^
-H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0" ^
--data-raw ^"------WebKitFormBoundaryHTC3EJwKAxoAA7BI^

Content-Disposition: form-data; name=^\^"video_link^\^"^

^

https://v.douyin.com/iLcmh9A5/^

------WebKitFormBoundaryHTC3EJwKAxoAA7BI^

Content-Disposition: form-data; name=^\^"my_csrf_token^\^"^

^

IjZhMWI1NGE5MGQwZDlhNjc1MzEwODBkYzdhYTJiMGZiMmY2YWJlZjIi.Zh-SlQ.VQinlJ7f227MO8AAE6ZEuYDaK4Q^

------WebKitFormBoundaryHTC3EJwKAxoAA7BI--^

^"

把上面从浏览器F12 copy的cmd curl命令 运行有 成功返回

curl “https://v.2urs.com/get_csrf_token" ^ 得到 “ImM1ZDQ2MWNkNjZiODcxNDA2NmI5M2FkMTA0YTQ5NDI1ZmRlNDIxNTAi.Zh-TUw.VSCvekkR7bAODIsOa0P0N_-7cN4”

把这个值替换上面的cmd curl 。为什么不可以了 报错: { “error”: “The CSRF tokens do not match.” } 把cookie 去掉 然后报错 { “error”: “The CSRF session token is missing.” } 为什么?

 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
31
32
33
34
35
 curl "https://v.2urs.com/download" ^
-H "accept: */*" ^
-H "accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7" ^
-H "content-type: multipart/form-data; boundary=----WebKitFormBoundaryHTC3EJwKAxoAA7BI" ^
-H "cookie: _ga=GA1.2.204225576.1709769565; Hm_lvt_b3aa9ed2616f88781f9792c2a0cafa9c=1709515900,1709531436,1709775119,1710211332; _gid=GA1.2.803156679.1713323002; _ga_FYYVZP7K0Z=GS1.2.1713340526.35.0.1713340526.60.0.0; session=eyJjc3JmX3Rva2VuIjoiNDNhZDZiYjExMzg4YTRlZTU2ZmY5MGRjNzJhMDgwZTRjYTVhYmU1OCJ9.Zh-WZQ.mNwH8GiyZmZQcQx7T40l-Qb0XeI" ^
-H "origin: https://v.2urs.com" ^
-H "referer: https://v.2urs.com/douyin/en/index-csrf.html" ^
-H ^"sec-ch-ua: ^\^"Microsoft Edge^\^";v=^\^"123^\^", ^\^"Not:A-Brand^\^";v=^\^"8^\^", ^\^"Chromium^\^";v=^\^"123^\^"^" ^
-H "sec-ch-ua-mobile: ?0" ^
-H ^"sec-ch-ua-platform: ^\^"Windows^\^"^" ^
-H "sec-fetch-dest: empty" ^
-H "sec-fetch-mode: cors" ^
-H "sec-fetch-site: same-origin" ^
-H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0" ^
--data-raw ^"------WebKitFormBoundaryHTC3EJwKAxoAA7BI^

Content-Disposition: form-data; name=^\^"video_link^\^"^

^

https://v.douyin.com/iLcmh9A5/^

------WebKitFormBoundaryHTC3EJwKAxoAA7BI^

Content-Disposition: form-data; name=^\^"my_csrf_token^\^"^

^

IjQzYWQ2YmIxMTM4OGE0ZWU1NmZmOTBkYzcyYTA4MGU0Y2E1YWJlNTgi.Zh-WZQ.3s872SAbVX7LjTva4CvAC0Wf6RQ^

------WebKitFormBoundaryHTC3EJwKAxoAA7BI--^

^"

你的问题涉及到CSRF(跨站请求伪造)令牌的更换。 在浏览器环境中,每次当用户界面完成交互后,例如一个HTTP请求,此时CSRF令牌可能被话务器刷新,于是下一次请求需要使用新的令牌。新令牌通常被存储在cookie中,然后该令牌将被用于验证后续的请求。 然而,在你使用curl的情况下,你手动获取了一个新的CSRF令牌,“ImM1ZDQ2MWNkNjZiODcxNDA2NmI5M2FkMTA0YTQ5NDI1ZmRlNDIxNTAi.Zh-TUw.VSCvekkR7bAODIsOa0P0N_-7cN4”,并将其放在你下载请求的表单中。但在从服务器返回新的CSRF令牌时,服务器通常也会在Set-Cookie响应头中设置一个新的会话cookie。这个新的会话cookie应该伴随新的CSRF令牌一起在后续请求中使用。 当缺少这个新的会话cookie,或者其中的CSRF会话令牌与提交的CSRF令牌不匹配时,服务器将拒绝该请求,并且你会收到错误提示"The CSRF tokens do not match.” 或者 “The CSRF session token is missing.” 通常,浏览器会自动处理新的session cookie,但在使用curl时,你需要手动处理。在你获取新的CSRF令牌的响应里,查看Set-Cookie响应头,并将服务器设置的新的会话cookie加入到你的下载请求的cookie头部中。

这样,cookies.txt文件里就保存了从服务器返回的所有cookies,包括session cookie。 之后,你可以使用-b或–cookie选项来在后续的请求中发送这些cookie。以下是包含cookie的请求示例:

把替换 cookie session的值用cookies.txt 相关的cookie值替换 或者

1
 curl -b cookies.txt "https://v.test.com/download" -H ...

按照你这种方式https://v.test.com/get_csrf_token得到csrf 和cookie 。然后curl请求https://v.test.com/download 带 新cookeie和csrf和video_link 就可以成功有下载数据返回了。。怎么防止这种方式来破解csrf呢,和写个程序就可以调用我网站进行解析接口下载了?

这其实并不是一种"破解"方式,因为这种进行的是合法的操作流程:获取CSRF令牌,然后发送数据。这和手动在网站上点击并发送数据的道理是相同的。网站的CSRF防护主要是用来防止第三方网站伪造请求,不是用来防止合法用户的请求。当前你的网站已经对CSRF进行了防护,因而理论上是安全的。 不过,有一个要注意的安全隐患:任何人都能获取CSRF令牌并发送请求。如果你的网站有些敏感操作,你可能需要对其进行额外的保护,简单的CSRF防护可能是不够的。这种情况下,你可能需要添加一些额外的措施,比如: 验证码:在敏感操作需要用户输入验证信息,例如短信验证码或邮箱链接等。 第二步验证:例如使用短信、邮件或者安全问题要求用户再次确认操作。 操作频率限制:比如同一用户(基于IP或者账号判断)一段时间内只允许进行有限次数的操作,可以有效防止滥用。 登录校验:未注册/登录用户无法进行操作。 综上,仅仅依赖CSRF防护可能是不够的,对于安全性要求高的操作,建议加入额外的安全措施。

如何添加验证码来增强CSRF保护? 什么是第二步验证?如何在网站上实现它? 如何设置操作频率限制以防止滥用?

随机文章