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设置:

  1. pkg/admin/admin.go
  2. pkg/login/login.go
  3. pkg/register/register.go

修改后需要重新生成CodeQL数据库(如需覆盖旧数据库,需先删除旧的再生成新的)。

3. CodeQL分析原理

3.1 分析目标

识别以下两种情况:

  1. 未设置HttpOnly属性的Cookie
  2. 设置了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设置点,即:

  1. 未设置HttpOnly属性的Cookie
  2. 设置了HttpOnly但值为false的Cookie

7. 总结

通过本教程,我们学习了:

  1. 如何使用CodeQL定义Source和Sink
  2. 如何构建数据流分析配置
  3. 如何使用isSanitizer过滤无害数据流
  4. 如何编写完整的CodeQL查询来检测Golang中Cookie未设置HttpOnly的安全问题

这种方法可以扩展到其他类似的安全问题检测,如Secure标志、SameSite属性等的检查。

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.go pkg/login/login.go pkg/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查询语句: 封装为Sink类: 3.2.2 Source定义 Source是 http.SetCookie 方法接收的第二个参数,即 Cookie 结构体的指针。 查找所有结构体: 筛选出net/http.Cookie结构体: 封装为Source类: 4. 数据流分析 4.1 基本数据流分析 定义TaintConfig来追踪从Source到Sink的数据流: 4.2 过滤已设置HttpOnly=true的情况 使用 isSanitizer 过滤掉已经正确设置HttpOnly=true的Cookie: 初始版本(有缺陷): 改进版本(解决数据流识别问题): 其中 node = n.getAPredecessor*() 表示node是n的前置数据流节点,数据可以在0个或多个步骤中从node流到n。 5. 完整CodeQL查询脚本 6. 结果分析 运行上述脚本后,CodeQL将筛选出存在问题的Cookie设置点,即: 未设置HttpOnly属性的Cookie 设置了HttpOnly但值为false的Cookie 7. 总结 通过本教程,我们学习了: 如何使用CodeQL定义Source和Sink 如何构建数据流分析配置 如何使用isSanitizer过滤无害数据流 如何编写完整的CodeQL查询来检测Golang中Cookie未设置HttpOnly的安全问题 这种方法可以扩展到其他类似的安全问题检测,如Secure标志、SameSite属性等的检查。