Codeql分析Vulnerability-GoApp
字数 1299 2025-08-15 21:32:26
CodeQL分析Golang中Cookie未设置HttpOnly漏洞的教学文档
1. 概述
本教学文档将详细介绍如何使用CodeQL静态分析工具来检测Golang Web应用程序中Cookie未设置HttpOnly属性的安全问题。HttpOnly是Cookie的一个重要安全属性,设置后可以防止JavaScript通过document.cookie访问该Cookie,从而降低XSS(跨站脚本攻击)的风险。
2. 准备工作
2.1 环境要求
- CodeQL CLI工具
- CodeQL Go语言分析库
- 目标项目:Vulnerability-goapp(一个用于教育的易受攻击的Golang Web应用程序)
2.2 项目修改
由于原项目中所有Cookie均未设置HttpOnly,缺乏对比性,需要先对以下文件进行修改,添加HttpOnly设置:
pkg/admin/admin.gopkg/login/login.gopkg/register/register.go
修改后需要重新生成CodeQL数据库(如需覆盖旧数据库,需先删除旧的再生成新的)。
3. CodeQL分析原理
3.1 分析目标
识别以下两种情况:
- 未设置HttpOnly属性的Cookie
- 设置了HttpOnly但值为false的Cookie(虽然不常见,但需要防范)
3.2 确定Source和Sink
3.2.1 Sink定义
Sink点是设置Cookie的位置,即http.SetCookie方法的第二个参数(需要设置的Cookie值)。
Sink查询语句:
import go
from DataFlow::Node sink
where exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("net/http", "SetCookie") and
c.getArgument(1) = sink
)
select sink
封装为Sink类:
private class Sink extends DataFlow::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("net/http", "SetCookie") and
c.getArgument(1) = this
)
}
}
3.2.2 Source定义
Source是http.SetCookie方法接收的第二个参数,即Cookie结构体的指针。
查找所有结构体:
import go
from StructLit source
select source
筛选出net/http.Cookie结构体:
import go
from StructLit source
where source.getType().hasQualifiedName("net/http", "Cookie")
select source
封装为Source类:
private class Source extends DataFlow::Node {
Source() {
exists(StructLit s |
s.getType().hasQualifiedName("net/http", "Cookie") and
this.asExpr() = s
)
}
}
4. 数据流分析
4.1 基本数据流分析
定义TaintConfig来追踪从Source到Sink的数据流:
import go
private class Source extends DataFlow::Node { /* 同上 */ }
private class Sink extends DataFlow::Node { /* 同上 */ }
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "HttpOnly" }
override predicate isSource(DataFlow::Node source) {
source instanceof Source
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof Sink
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select source, sink
4.2 过滤已设置HttpOnly=true的情况
使用isSanitizer过滤掉已经正确设置HttpOnly=true的Cookie:
初始版本(有缺陷):
override predicate isSanitizer(DataFlow::Node node) {
exists(Write w, Field f, DataFlow::Node rhs |
f.hasQualifiedName("net/http", "Cookie", "HttpOnly") and
w.writesField(node, f, rhs) and
rhs.getBoolValue() = true
)
}
改进版本(解决数据流识别问题):
override predicate isSanitizer(DataFlow::Node node) {
exists(Write w, Field f, DataFlow::Node n, DataFlow::Node rhs |
f.hasQualifiedName("net/http", "Cookie", "HttpOnly") and
w.writesField(n, f, rhs) and
rhs.getBoolValue() = true and
node = n.getAPredecessor*()
)
}
其中node = n.getAPredecessor*()表示node是n的前置数据流节点,数据可以在0个或多个步骤中从node流到n。
5. 完整CodeQL查询脚本
/**
* @name Cookie未设置httponly
* @description Cookies包含一个HTTPOnly的设置选项,可以使此cookie不能被js读取,而只能用于HTTP请求。
* @kind path-problem
* @problem.severity error
* @precision low
* @id go/Cookie-not-set-httponly
* @tags security
*/
import go
import DataFlow::PathGraph
private class Source extends DataFlow::Node {
Source() {
exists(StructLit s |
s.getType().hasQualifiedName("net/http", "Cookie") and
this.asExpr() = s
)
}
}
private class Sink extends DataFlow::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("net/http", "SetCookie") and
c.getArgument(1) = this
)
}
}
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "HttpOnly" }
override predicate isSource(DataFlow::Node source) {
source instanceof Source
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof Sink
}
override predicate isSanitizer(DataFlow::Node node) {
exists(Write w, Field f, DataFlow::Node n, DataFlow::Node rhs |
f.hasQualifiedName("net/http", "Cookie", "HttpOnly") and
w.writesField(n, f, rhs) and
rhs.getBoolValue() = true and
node = n.getAPredecessor*()
)
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Cookie-not-set-httponly in $@.", source.getNode(), "here"
6. 结果分析
运行上述脚本后,CodeQL将筛选出存在问题的Cookie设置点,即:
- 未设置HttpOnly属性的Cookie
- 设置了HttpOnly但值为false的Cookie
7. 总结
通过本教程,我们学习了:
- 如何使用CodeQL定义Source和Sink
- 如何构建数据流分析配置
- 如何使用isSanitizer过滤无害数据流
- 如何编写完整的CodeQL查询来检测Golang中Cookie未设置HttpOnly的安全问题
这种方法可以扩展到其他类似的安全问题检测,如Secure标志、SameSite属性等的检查。