首頁  >  文章  >  運維  >  Codeql如何分析cookie未啟用httponly的問題

Codeql如何分析cookie未啟用httponly的問題

PHPz
PHPz轉載
2023-05-17 17:25:591265瀏覽

今天我們利用codeql分析下「cookie未啟用httponly「這類的安全性問題,因此加深自己對codeql的使用。如果效果良好,可以考慮修復Vulnerability-goapp的其他漏洞。

分析go程式時必須額外下載codeql-go

說明

稽核物件

Vulnerability-goapp:Vulnerable golang Web application for education。

修改

由於在該專案中所有的 Cookie 都沒有設定 http-only 屬性,因此我們需要先修改才能進行比較。以下是對原句的重寫: 記錄修改:在某些cookie設定中增加http-only選項。

pkg\admin\admin.go修正如下。
Codeql如何分析cookie未啟用httponly的問題

pkg\login\login.go修正如下。
Codeql如何分析cookie未啟用httponly的問題

pkg\register\register.go修改如下。
Codeql如何分析cookie未啟用httponly的問題

修改後記得重新產生一次database(如果需要覆蓋舊的DATabase的話,則需要先刪除舊的再產生新的。

#目的

就是透過codeql腳本來發現其中未設定httponly和設定了httponly的但httponly的值為false(一般不會這樣,但保不齊有)的這樣存在漏洞的點。

#確定Source和Sink

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

運行後可獲得以下結果,點擊任意條目都會跳到複合要求的程式碼段下。
Codeql如何分析cookie未啟用httponly的問題

##我們將其轉換成Sink類,如下。

private class Sink extends DataFlow::Node {
  Sink() {
    exists(DataFlow::CallNode c |
      c.getTarget().hasQualifiedName("net/http", "SetCookie") and c.getArgument(1) = this
    )
  }
}
這樣之後我們透過將變數定義成Sink的話,就是指符合條件的所有程式碼片段,例如:

import go

private class Sink extends DataFlow::Node {
  Sink() {
    exists(DataFlow::CallNode c |
      c.getTarget().hasQualifiedName("net/http", "SetCookie") and c.getArgument(1) = this
    )
  }
}

from Sink s
select s
運行後會獲得同樣的結果。

Source定義

然後我們再來確定Source,從http.SetCookie方法接收的參數來看,實際第二個參數是接收一個Cookie的結構體的指標。


Codeql如何分析cookie未啟用httponly的問題Codeql如何分析cookie未啟用httponly的問題

所以我們先要找出這樣一個結構體,我們可以先把專案中所有的結構體列出來。

codeql-go中關於結構體的定義如下。


Codeql如何分析cookie未啟用httponly的問題

所以我們的查詢腳本例如。

import go

from StructLit source
select source
也如我們預期的一樣列出了所有的結構體。


Codeql如何分析cookie未啟用httponly的問題

然後接下來就是剔除其他不相干的內容,對型別做限制。

關於hasQualifiedName方法,在各種Codeql-go中的各種型別都有相同的方法,定義如下,標記物件的是在屬於哪個包,叫什麼名。


Codeql如何分析cookie未啟用httponly的問題

如果不確定的話,可以通過,getPackage和getName列印相關字段,例如。

import go

from StructLit source
// where source.getType().hasQualifiedName("net/http", "Cookie")
select source.getType().getPackage(), source.getType().getName()
結果如下。


Codeql如何分析cookie未啟用httponly的問題

我們可以找到source定義,例如。

import go

from StructLit source
where source.getType().hasQualifiedName("net/http", "Cookie")
select source

同樣轉換成DataFlow::Node的子類別。Codeql如何分析cookie未啟用httponly的問題

private class Source extends DataFlow::Node {
  Source() {
    exists(StructLit s | s.getType().hasQualifiedName("net/http", "Cookie") and this.asExpr() = s)
  }
}
TaintConfig定義

簡單的資料流

有了Source和Sink,簡單定義TaintConfig,就能獲得所有從Source到Sink的資料流。

import go

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 }
}

from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select source, sink
結果如下:


Codeql如何分析cookie未啟用httponly的問題

剔除

#然而,我們仍未移除設定了httponly=true的部分。因此需要加入限定條件,即將設有HttpOnly屬性為true的資料流從結果中排除。

我們可以 CodeQL 提供的 TaintTracking::isSanitizer,來篩選無害節點:

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
    )
  }

运行结果如下,但有一处地方需要注意。
Codeql如何分析cookie未啟用httponly的問題红框中实际有对HttpOnly进行设置,但我们的脚本并不能识别这样的一个数据流。后面试了各种方法,最终找到一种解决方式,将isSanitizer修改成以下内容。

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*()n
    )
  }

其中node=n.getAPredecessor*()是说node是n的前置数据流节点,数据可以在0个或多个步骤中从node流到n。

最终脚本

加上一些信息,模仿官方的示例,最终脚本如下。

/**
 * @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"

最终筛选出存在问题的内容。
Codeql如何分析cookie未啟用httponly的問題

以上是Codeql如何分析cookie未啟用httponly的問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除