词法分析在安全产品中的应用
问题背景
最近分析了一些waf、rasp等安全产品,发现核心检测逻辑非常依赖词法分析。
总结一点东西:
- 词法分析是什么?
- 举个例子:OpenRASP怎么用到词法分析做安全策略?
- 怎么实现词法分析?
- 还有哪些安全防护产品用到词法分析?
分析过程
词法分析是什么?
词法分析可以将字符串按照自己的规则变成一串token。
比如一个算术表达式 1+2*3
,按照一定规则做词法分析后可以变成 NUM ADD NUM MUL NUM
一串token。
编程语言在执行前也要做词法分析,比如Python词法分析结果是这样子的
1 | ➜ ~ python -m tokenize |
安全产品怎么用到词法分析做安全策略?
拿OpenRASP举例,OpenRASP检测SQL注入、命令执行时核心检测算法非常依赖词法分析。
先看看请求是怎么到检测插件的
OpenRASP可以作为PHP扩展保护PHP应用,在扩展被加载时hook了很多执行sql的函数,比如openrasp项目
agent/php5/hook/openrasp_mysqli.cc
文件中可以看到hook了mysqli模块的函数。1
2
3
4
5
6
7
8
9/**
* mysqli相关hook点
*/
...
PRE_HOOK_FUNCTION(mysqli_query, SQL);
POST_HOOK_FUNCTION(mysqli_query, SQL_ERROR);
...当业务代码在做数据库查询时,如果调用
mysqli_query
等函数执行SQL,就会在执行SQL前经过OpenRASP的检测策略。检测策略文件是JavaScript写的,代码位置在
plugins/official/plugin.js
。在执行SQL注入检查时,会传入即将执行的SQL(如 “select * from users where a=1”)和完整的请求信息(包含请求参数)。
1
2
3...
plugin.register('sql', function (params, context) { //params.query包含完整sql,context包含完整请求
...OpenRASP怎么做SQL注入检测?
SQL注入检测策略默认开启了三种:
* 词法分析后,判断用户输入是否改变SQL执行逻辑 * 词法分析后,判断SQL语句是否有写文件操作、使用黑名单函数等 * sql server执行异常
第一类SQL注入检测策略:对即将执行的sql语句做分词,判断用户的输入占用了几个token,正常情况下,用户输入应该只占有一个token。 比如最终执行sql是select id from user where name=”user_input_name”, 正常请求时 “user_input_name” 会变成一个字符串token。如果碰到恶意请求闭合了双引号,用户输入就至少占用两个token。
详细可见官方文档 OpenRASP v0.20 发布 | 性能提升与零规则漏洞检测。
实现的代码在
plugins/official/plugin.js
文件1
2
3
4
5
6
7// raw_tokens包含有词法分析得到的token串
// userinput_idx是用户输入在最终执行的sql的开始位置
if (is_token_changed(raw_tokens, userinput_idx, value.length, distance, is_sql=true)) {
reason = _("SQLi - SQL query structure altered by user input, request parameter name: %1%, value: %2%", [name, value])
return true
}第二类SQL注入检测策略:检查分词后的token串中是否命中规则。
比如 为了对抗”利用SQL注入中写webshell”这种攻击方式,就检查最终执行的sql语句是否包含 [“into”,”outfile”]和[“into”,”dumpfile”] 两类token
select "webshell.txt" into outfile '/var/www/webshell.php'
可以用来写入Webshell检测策略的实现代码也在 plugin.js 中可以看到
1
2
3
4
5
6
7
8else if (features['into_outfile'] && i < tokens_lc.length - 2 && tokens_lc[i] == 'into')
{
if (tokens_lc[i + 1] == 'outfile' || tokens_lc[i + 1] == 'dumpfile')
{
reason = _("SQLi - Detected INTO OUTFILE phrase in sql query")
break
}
}命令执行检测同样也依赖词法分析。
可以看出来OpenRASP中词法分析在sql注入、命令执行检测算法中目前很重要。
怎么实现词法分析?
OpenRASP有两个JS接口可以获取分析后的token串,见sql_tokenize
实现接口的代码在openrasp-v8项目中base/flex/flex.cc
文件,这个文件是flex工具生成的,原始的规则文件并没有开源出来。
1 | static sql_tokenize(query) { |
从实现角度上看,词法分词可以分为三类:
- 借助工具,如flex、antlr。openrasp就是用借助flex做的
- 纯手写实现,比如 libinjection
- combinator库等半自动
哪些安全产品用到了词法分析?
- openrasp
- waf
- libinjection
- 命令执行防护
- xss防护
- sql注入防护
- hids
- webshell检测
- db防火墙
- 代码混淆与反混淆
- …
上面的部分产品除了用到词法分析,还会用到语法分析、语义分析。
总结
主要还是围绕OpenRASP来写的这篇文章,没有细讲词法分析的实现、做项目时应该用工具还是完全手写词法分析、语法分析这类检测引擎的误报和漏报场景等问题。
关于词法分析、语法分析的原理、算法和实现,推荐看 编译原理之美 这个课程,一级棒。