日志注入¶
ID: py/log-injection
Kind: path-problem
Security severity: 7.8
Severity: error
Precision: medium
Tags:
- security
- external/cwe/cwe-117
Query suites:
- python-security-extended.qls
- python-security-and-quality.qls
如果将未经清理的用户输入写入日志条目,恶意用户可能能够伪造新的日志条目。
如果用户提供了一些在显示日志输出时会被解释的字符,则可能会发生伪造。如果日志以纯文本文件形式显示,则恶意用户可以使用换行符来创建多个日志条目的外观。如果日志以 HTML 形式显示,则可以包含任意 HTML 来伪造日志条目。
建议¶
在记录用户输入之前,应对其进行适当的清理。
如果日志条目是纯文本,则应从用户输入中删除换行符,例如使用 replace(old, new)
或类似方法。还应注意,用户输入在日志条目中应清晰标记,并且恶意用户不能以其他方式造成混淆。
对于将在 HTML 中显示的日志条目,用户输入应在记录之前进行 HTML 编码,以防止伪造和其他形式的 HTML 注入。
示例¶
在示例中,用户提供的名称使用日志输出函数(logging.info
或 app.logger.info
等)记录。在这四种情况下,用户提供的名称没有经过处理。如果恶意用户提供 Guest%0D%0AUser name: Admin
作为参数,则日志条目将被分为两行,第一行是 User name: Guest
code>,第二行是 User name: Admin
。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Desc :Log Injection
"""
from flask import Flask
from flask import request
from django.utils.log import request_logger
import logging
logging.basicConfig(level=logging.DEBUG)
app = Flask(__name__)
@app.route('/bad1')
def bad1():
name = request.args.get('name')
app.logger.info('User name: ' + name) # Bad
return 'bad1'
@app.route('/bad2')
def bad2():
name = request.args.get('name')
logging.info('User name: ' + name) # Bad
return 'bad2'
@app.route('/bad3')
def bad3():
name = request.args.get('name')
request_logger.warn('User name: ' + name) # Bad
return 'bad3'
@app.route('/bad4')
def bad4():
name = request.args.get('name')
logtest = logging.getLogger('test')
logtest.debug('User name: ' + name) # Bad
return 'bad4'
if __name__ == '__main__':
app.debug = True
handler = logging.FileHandler('log')
app.logger.addHandler(handler)
app.run()
在一个良好的示例中,程序使用 replace
函数对用户提供的参数进行处理,并将 \r\n
和 \n
替换为空字符。这在一定程度上减少了日志注入漏洞的发生。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Desc :Log Injection
"""
from flask import Flask
from flask import request
import logging
logging.basicConfig(level=logging.DEBUG)
app = Flask(__name__)
@app.route('/good1')
def good1():
name = request.args.get('name')
name = name.replace('\r\n','').replace('\n','')
logging.info('User name: ' + name) # Good
return 'good1'
if __name__ == '__main__':
app.debug = True
handler = logging.FileHandler('log')
app.logger.addHandler(handler)
app.run()