Flask 第五课数据传输加密
tags:
- Flask
- 2019千锋教育
categories:
- flask
- 数据加密
- 反爬虫技术
第一节 数据准备
- 数据加密前视图函数views.py和news_list.html如下。
@blue.route('/addnews/')
def add_news():
news = News()
news.n_title = "小搞怪 %d" % random.randrange(1000)
news.n_content = "社会福利 %d" % random.randrange(100)
db.session.add(news)
db.session.commit()
return '添加新闻列表成功'
@blue.route('/getnews/')
def get_news():
news_list = News.query.all()
return render_template('news_list.html', news_list=news_list)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>News list</title>
</head>
<body>
<h2>今日新闻</h2>
<ul>
{% for news in news_list %}
<li>{{ news.n_content }}</li>
{% endfor %}
</ul>
</body>
</html>
- 爬虫脚本
import requests
def get_data():
response = requests.get("http://127.0.0.1:5000/getnews/")
print(response.content.decode("utf-8"))
if __name__=="__main__":
get_data()
第二节 JS加载和数据加密
2.1 通过js加载出数据
- 创建数据html, news_content.html页面。
- {{ news_content|safe }} 当成html格式输出。
<!--news_list.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>News list</title>
</head>
<body>
<h2>今日新闻</h2>
<script type="text/javascript">
document.write("{{ news_content|safe }}")
</script>
<!--{ news_content|safe }}-->
</body>
</html>
<!--news_content.html, 写成一行的格式(否则加载到news_list会报错)-->
<ul>{% for news in news_list %}<li>{{ news.n_content }}</li>{% endfor %}</ul>
# views.py
@blue.route('/getnews/')
def get_news():
news_list = News.query.all()
news_content = render_template("news_content.html", news_list=news_list)
return render_template('news_list.html', news_content=news_content)
2.2 对数据进行加密
- 我们使用的解密js函数如下。show.js
- 它先对整体字符串解密,去掉前后约定字符串后,再次解密。
function base64Decode(input) {
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
};
output = _utf8_decode(output);
return output;
}
function showDeHtml(J1) {
return base64Decode(
(base64Decode(J1)["\x72\x65\x70\x6c\x61\x63\x65"]('\x43\x48\x4b\x61\x32\x47\x46\x4c\x31\x74\x77\x68\x4d\x44\x68\x45\x5a\x56\x66\x44\x66\x55\x32\x44\x6f\x5a\x48\x43\x4c\x5a\x6b', ''))
["\x72\x65\x70\x6c\x61\x63\x65"]('\x70\x4f\x71\x33\x6b\x52\x49\x78\x73\x32\x36\x72\x6d\x52\x74\x73\x55\x54\x4a\x76\x42\x6e\x39\x5a', '')
)
}
/**
*
* base64Decode(
* base64Decode(content)['replace']('CHKa2GFL1twhMDhEZVfDfU2DoZHCLZk',''))
* ['replace']('pOq3kRIxs26rmRtsUTJvBn9Z','')
*
* base64Decode( base64Decode(content).replace('CHKa2GFL1twhMDhEZVfDfU2DoZHCLZk', '').replace('pOq3kRIxs26rmRtsUTJvBn9Z', '') )
*
*/
- 后端对返回数据进行加密
import base64
@blue.route('/getnews/')
def get_news():
news_list = News.query.all()
news_content = render_template("news_content.html", news_list=news_list)
# 字符串转二进制 加密后成二进制在转成字符串
encode_content = base64.standard_b64encode(news_content.encode("utf-8")).decode("utf-8")
print(encode_content)
# 拼串 加入和前端约定好的前后字符串
add_content_encode_content = "CHKa2GFL1twhMDhEZVfDfU2DoZHCLZk" + encode_content + "pOq3kRIxs26rmRtsUTJvBn9Z"
print(add_content_encode_content)
encode_content_twice = base64.standard_b64encode(add_content_encode_content.encode("utf-8")).decode("utf-8")
print(encode_content_twice)
return render_template('news_list.html', news_content=news_content, encode_content_twice=encode_content_twice)
- 前端对返回数据进行解析。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>News list</title>
<script type="text/javascript" src="{{ url_for('static', filename='js/show.js') }}"></script>
</head>
<body>
<h2>今日新闻</h2>
<script type="text/javascript">
/*document.write("{{ news_content|safe }}");*/
document.write(showDeHtml("{{ encode_content_twice|safe }}"));
</script>
<!--{ news_content|safe }}-->
</body>
</html>
- 如果在直接爬取网页信息,就只能看到一堆加密的字符串。但是我们可以看到有一个自己的show.js资源。
- 如果我们把它下载下来,对加密算法进行分析解密。还是可以获取到我们的数据。下面我们尝试吧show.js给隐藏掉。
- 也可以使用浏览器的JS容器加载,由python文件调用。
第三节 隐藏加密js文件
- 写一个接口由接口返回我们的js文件。
- 接口具有时效性,超过1秒自动时效
@blue.route('/getshow/')
def get_show():
import os, time
from flask import request
from App.settings import BASE_DIR
# 接收前端的时间参数
t = request.args.get("t")
print(t)
# python中以秒为计数单位,其他语言以毫秒计数单位
c = time.time() * 1000
# 捕获异常(防止手动乱输入)
try:
t = int(t)
except:
return "2"
# 1秒之内请求可以正常返回js
if c > t and c - t < 1000:
with open(os.path.join(BASE_DIR, "static\js\show.js"), 'r') as file:
js_content = file.read()
print(js_content)
return js_content
else:
return "1"
- 动态访问接口获取js文件。并传入时间参数。
- 这种方法有效避免直接通过页面获取js文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>News list</title>
<!-- 传入时间下面方法不适用因为用不了JS的时间函数,使用动态加载 -->
<!--<script type="text/javascript" src="{{ url_for('blue.get_show') }}"></script>-->
<script type="text/javascript">
// 这个在前台控制台Elements中才能看见 source中看不到
document.write('<script type="text/javascript" src="/getshow/?t='+Date.parse(new Date())+'"><\/script>');
</script>
</head>
<body>
<h2>今日新闻</h2>
<script type="text/javascript">
/*document.write("{{ news_content|safe }}");*/
document.write(showDeHtml("{{ encode_content_twice|safe }}"));
</script>
<!--{ news_content|safe }}-->
</body>
</html>
第四节 总结
-
如果通过爬虫文件,直接爬取。会返回一堆js代码。
-
爬虫获取的是前端控制台Source的内容,而不是Element的内容。
-
当然这种反爬虫也不是最强大的,我们可以通过**浏览器的console输出加密函数*
-
爬虫基本步奏
- 数据获取
- 麻烦
- 数据提取
- 数据存储
- 数据清洗
- 数据获取
-
反爬
- 数据加密反爬
- 在服务端对数据进行特定算法的加密
- 在客户端进行数据的解密
- 浏览器还是可破解的
- Android或IOS移动端,破解率基本为零