如何在 Flask-SocketIO 中转义 HTML 个字符?
How to escape HTML characters in Flask-SocketIO?
基于 GitHub 上的示例,这是我的 Python 脚本:
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode='eventlet')
@app.route('/')
def index():
return render_template('index.html')
@socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': message['data'], 'count': session['receive_count']})
if __name__ == '__main__':
socketio.run(app, debug=True)
这是 HTML 模板:
<!DOCTYPE HTML>
<html>
<head>
<script src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
<script charset="utf-8">
$(document).ready(function(){
namespace = '/test'; // change to an empty string to use the global namespace
// the socket.io documentation recommends sending an explicit package upon connection
// this is specially important when using the global namespace
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
// event handler for server sent data
// the data is displayed in the "Received" section of the page
socket.on('my response', function(msg) {
$('#log').append('<br>Received #' + msg.count + ': ' + msg.data);
});
// handlers for the different forms in the page
// these send data to the server in a variety of ways
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
});
</script>
</head>
<body>
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
<h2>Receive:</h2>
<div id="log"></div>
</body>
</html>
一切正常。但问题是用户可以在消息中使用 任何 HTML 标签。
例如:
我认为这 很小 危险。因为任何用户也可以 运行 一些 JavaScript 代码并广播它。然后每个客户都会运行它。
有没有什么方法可以使用 Jinja 自动转义输出,或者还有其他方法吗?
但是,我发现的方法是,我们可以转义脚本中的 HTML 个字符,例如:
import jinja2
# other code here
@socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': jinja2.escape(message['data']), 'count': session['receive_count']})
# ^^^^^^^^^^^^^^ use jinja2 escape the output before send it to the clients.
演示输出:
这里是 Flask-SocketIO 作者。
示例应用程序是作为如何发送和接收消息的快速示例,我不认为它是如何安全处理用户输入的示例。
但是这个观点很好,我现在更新了 example app 以正确处理用户输入。如何执行此操作取决于应用程序。对于这个例子,我选择在客户端使用 jQuery:
进行转义
$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());
基于 GitHub 上的示例,这是我的 Python 脚本:
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode='eventlet')
@app.route('/')
def index():
return render_template('index.html')
@socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': message['data'], 'count': session['receive_count']})
if __name__ == '__main__':
socketio.run(app, debug=True)
这是 HTML 模板:
<!DOCTYPE HTML>
<html>
<head>
<script src="//code.jquery.com/jquery-1.4.2.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
<script charset="utf-8">
$(document).ready(function(){
namespace = '/test'; // change to an empty string to use the global namespace
// the socket.io documentation recommends sending an explicit package upon connection
// this is specially important when using the global namespace
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
// event handler for server sent data
// the data is displayed in the "Received" section of the page
socket.on('my response', function(msg) {
$('#log').append('<br>Received #' + msg.count + ': ' + msg.data);
});
// handlers for the different forms in the page
// these send data to the server in a variety of ways
$('form#emit').submit(function(event) {
socket.emit('my event', {data: $('#emit_data').val()});
return false;
});
});
</script>
</head>
<body>
<form id="emit" method="POST" action='#'>
<input type="text" name="emit_data" id="emit_data" placeholder="Message">
<input type="submit" value="Echo">
</form>
<h2>Receive:</h2>
<div id="log"></div>
</body>
</html>
一切正常。但问题是用户可以在消息中使用 任何 HTML 标签。
例如:
我认为这 很小 危险。因为任何用户也可以 运行 一些 JavaScript 代码并广播它。然后每个客户都会运行它。
有没有什么方法可以使用 Jinja 自动转义输出,或者还有其他方法吗?
但是,我发现的方法是,我们可以转义脚本中的 HTML 个字符,例如:
import jinja2
# other code here
@socketio.on('my event', namespace='/test')
def test_message(message):
session['receive_count'] = session.get('receive_count', 0) + 1
emit('my response',
{'data': jinja2.escape(message['data']), 'count': session['receive_count']})
# ^^^^^^^^^^^^^^ use jinja2 escape the output before send it to the clients.
演示输出:
这里是 Flask-SocketIO 作者。
示例应用程序是作为如何发送和接收消息的快速示例,我不认为它是如何安全处理用户输入的示例。
但是这个观点很好,我现在更新了 example app 以正确处理用户输入。如何执行此操作取决于应用程序。对于这个例子,我选择在客户端使用 jQuery:
进行转义$('#log').append('<br>' + $('<div/>').text('Received #' + msg.count + ': ' + msg.data).html());