Go SDK
pkg/crtsh 是整个项目的事实来源,也可以直接 import 用在你自己的 Go 程序里。
安装
bash
go get github.com/cyberspacesec/crt.sh-skills/pkg/crtsh构造 Client
go
import crtsh "github.com/cyberspacesec/crt.sh-skills/pkg/crtsh"
client := crtsh.NewClient(
crtsh.WithTimeout(60*time.Second),
crtsh.WithRetryCount(5),
crtsh.WithDebug(true), // 打印请求/响应原文
crtsh.WithUserAgent("myapp/1.0"),
crtsh.WithBaseURL("https://crt.sh/"),
)默认值
无参数时:BaseURL https://crt.sh/、超时 30s、重试 3 次。
20 个方法速查
按用途分六大类,先用图定位你要的方法,再看下方代码:
flowchart TB ROOT["pkg/crtsh Client
20 个方法"] ROOT --> A["🔍 搜索与导出
4 个"] ROOT --> B["📄 证书与视图
8 个"] ROOT --> C["📡 Atom 与 add-chain
2 个"] ROOT --> D["🏛️ CA 与信息页
5 个"] ROOT --> E["🌐 Censys
1 个"] ROOT --> F["🔄 自动分页
1 个"] A --> A1["SearchCertificates
FetchSearchJSON/CSV/Atom"] B --> B1["GetCertificateByID
FetchRawCertificate
FetchASN1/Hierarchy/Graph/PV View
FetchCTEntryByID"] C --> C1["FetchAtomFeed
GenerateAddChainJSON"] D --> D1["FetchCAByID
FetchIssuerCertificatesByCAID
FetchAdvancedSearchPage
FetchCertificatePopulations
FetchInfoPage"] E --> E1["BuildCensysURL
纯字符串映射不发请求"] F --> F1["IterateCertificates
封装翻页回调"]
20 个方法"] ROOT --> A["🔍 搜索与导出
4 个"] ROOT --> B["📄 证书与视图
8 个"] ROOT --> C["📡 Atom 与 add-chain
2 个"] ROOT --> D["🏛️ CA 与信息页
5 个"] ROOT --> E["🌐 Censys
1 个"] ROOT --> F["🔄 自动分页
1 个"] A --> A1["SearchCertificates
FetchSearchJSON/CSV/Atom"] B --> B1["GetCertificateByID
FetchRawCertificate
FetchASN1/Hierarchy/Graph/PV View
FetchCTEntryByID"] C --> C1["FetchAtomFeed
GenerateAddChainJSON"] D --> D1["FetchCAByID
FetchIssuerCertificatesByCAID
FetchAdvancedSearchPage
FetchCertificatePopulations
FetchInfoPage"] E --> E1["BuildCensysURL
纯字符串映射不发请求"] F --> F1["IterateCertificates
封装翻页回调"]
搜索与导出
go
certs, pagination, err := client.SearchCertificates(ctx, crtsh.QueryParams{
Q: "example.com",
SearchType: "", // 空=通用;可填 "sha256"/"CN"/"dNSName" 等 22 种
Match: "ILIKE", // 7 种匹配模式
ExcludeExpired: true,
Deduplicate: true,
IssuerCAID: "12345", // 按 issuer CA ID 过滤
Group: "icaid", // 分组
Sort: 3, // 排序列
Dir: "v", // 降序
Linter: "zlint", // 边搜边 lint
LintType: "issues",
Page: 1,
PageSize: 50,
})go
jsonStr, _ := client.FetchSearchJSON(ctx, params)
csvStr, _ := client.FetchSearchCSV(ctx, params)
atomFeed, _ := client.FetchSearchAtomFeed(ctx, params)证书与视图
go
detail, _ := client.GetCertificateByID(ctx, 12345, crtsh.WithOCSPCheck())
rawPEM, _ := client.FetchRawCertificate(ctx, 12345)go
asn1HTML, _ := client.FetchASN1View(ctx, 12345)
hierHTML, _ := client.FetchHierarchyView(ctx, 12345)
graphHTML, _ := client.FetchGraphView(ctx, 12345)
pvHTML, _ := client.FetchPathValidationView(ctx, 12345)
ctPage, _ := client.FetchCTEntryByID(ctx, 111)Atom 与 add-chain / CA 与信息页 / Censys
go
feed, _ := client.FetchAtomFeed(ctx, "example.com", crtsh.WithExcludeExpired())
addChainJSON, _ := client.GenerateAddChainJSON(ctx, pemString)go
caPage, _ := client.FetchCAByID(ctx, 12345)
issPage, _ := client.FetchIssuerCertificatesByCAID(ctx, 12345)
advPage, _ := client.FetchAdvancedSearchPage(ctx)
popPage, _ := client.FetchCertificatePopulations(ctx, "RootOwner")
infoPage, _:= client.FetchInfoPage(ctx, "monitored-logs")go
// 纯字符串映射,不发请求
censysURL, _ := crtsh.BuildCensysURL("dNSName", "example.com")自动分页迭代
IterateCertificates 封装了翻页逻辑,回调每一条证书:
flowchart TD S["IterateCertificates(params, fn)"] --> P1["取第 1 页"] P1 --> CB["对每条证书调 fn"] CB --> CK{fn 返回 true?} CK -->|否| STOP["提前停止"] CK -->|是| NX{有下一页?} NX -->|是| P2["取下一页"] --> CB NX -->|否| DONE["结束"]
go
err := client.IterateCertificates(ctx, crtsh.QueryParams{
Q: "example.com", PageSize: 100,
}, func(cert crtsh.Certificate) bool {
fmt.Println(cert.ID, cert.NameValue)
return true // 返回 false 提前停止
})辅助函数
crtsh.SearchTypes() // 22 种搜索类型
crtsh.MatchModes() // 7 种匹配模式
crtsh.GroupModes() // 3 种分组
crtsh.SortDirections() // 3 种排序
crtsh.Linters() // 5 种 linter
crtsh.LintTypes() // 2 种 lint 输出
crtsh.CertPopulationGroups() // 人口统计分组
crtsh.ValidSearchTypes() // map[string]bool 快速查
crtsh.MatchModes() // 7 种匹配模式
crtsh.GroupModes() // 3 种分组
crtsh.SortDirections() // 3 种排序
crtsh.Linters() // 5 种 linter
crtsh.LintTypes() // 2 种 lint 输出
crtsh.CertPopulationGroups() // 人口统计分组
crtsh.ValidSearchTypes() // map[string]bool 快速查
强类型错误处理
每个 SDK 调用返回的 err 都能用类型断言函数精确分类,对症处理:
flowchart TD E["err"] --> N{IsNotFoundError?} N -->|是| N1["没找到
可降级为空结果"] N -->|否| R{IsRateLimitError?} R -->|是| R1["被限流
退避重试"] R -->|否| S{IsServerError?} S -->|是| S1["crt.sh 5xx
稍后重试"] S -->|否| P{IsParseError?} P -->|是| P1["响应解析失败
检查上游是否改版"] P -->|否| I{IsInvalidError?} I -->|是| I1["输入非法
校验参数"] I -->|否| O["其他错误
向上抛"]
可降级为空结果"] N -->|否| R{IsRateLimitError?} R -->|是| R1["被限流
退避重试"] R -->|否| S{IsServerError?} S -->|是| S1["crt.sh 5xx
稍后重试"] S -->|否| P{IsParseError?} P -->|是| P1["响应解析失败
检查上游是否改版"] P -->|否| I{IsInvalidError?} I -->|是| I1["输入非法
校验参数"] I -->|否| O["其他错误
向上抛"]
go
certs, _, err := client.SearchCertificates(ctx, params)
switch {
case crtsh.IsNotFoundError(err):
fmt.Println("没找到")
case crtsh.IsRateLimitError(err):
fmt.Println("被限流,退避重试")
case crtsh.IsServerError(err):
fmt.Println("crt.sh 5xx")
case crtsh.IsParseError(err):
fmt.Println("响应解析失败")
case crtsh.IsInvalidError(err):
fmt.Println("输入非法")
}示例项目
仓库 examples/ 下有 5 个可直接跑的示例:
01basic-search
基础域名搜索
02advance-search
高级搜索(多参数)
03ca-search
CA 调查
04get-cert-by-id
取证书详情
05page
分页
bash
cd examples/001-basic-search && go run .下一页