You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取域名的bigrams、trigrams及bigram_score用于DGA域名分类?

我懂你的痛点!之前用sentence.split()把域名拆成了“词”(但域名本身没有空格,其实就是一串连续字符),所以nltk返回的是词级别的n-grams,完全不是你要的字符级组合。别担心,调整一下代码就行,我给你一步步说清楚:

1. 获取字符级Bigrams & Trigrams

直接把域名字符串传给ngrams函数即可,不需要调用split()——因为域名本身就是我们要处理的字符序列,不需要按空格分词。

示例代码:

from nltk import ngrams

# 示例域名
domain = "example.com"

# 生成字符级Bigrams
char_bigrams = ngrams(domain, 2)
# 转成列表方便查看和后续处理
bigram_list = list(char_bigrams)
print("字符级Bigrams:", bigram_list)
# 输出:[('e', 'x'), ('x', 'a'), ('a', 'm'), ('m', 'p'), ('p', 'l'), ('l', 'e'), ('e', '.'), ('.', 'c'), ('c', 'o'), ('o', 'm')]

# 生成字符级Trigrams
char_trigrams = ngrams(domain, 3)
trigram_list = list(char_trigrams)
print("字符级Trigrams:", trigram_list)
# 输出:[('e', 'x', 'a'), ('x', 'a', 'm'), ('a', 'm', 'p'), ('m', 'p', 'l'), ('p', 'l', 'e'), ('l', 'e', '.'), ('e', '.', 'c'), ('.', 'c', 'o'), ('c', 'o', 'm')]
2. 计算Bigram Score(适配DGA检测场景)

对于DGA域名分类,Bigram Score一般是基于合法域名语料库的统计结果:先统计正常域名中每个bigram的出现概率,再计算目标域名中所有bigram的概率平均值(或总和)——得分越低,说明该域名的字符组合越少见,更大概率是DGA生成的。

示例实现:

from collections import defaultdict
from nltk import ngrams

# 假设你有一个合法域名数据集(实际可以使用公开的合法域名列表,比如Alexa Top 1M)
legitimate_domains = ["google.com", "facebook.com", "twitter.com", "github.com", "amazon.com"]

# 第一步:统计合法域名的Bigram频率
bigram_counts = defaultdict(int)
total_bigrams = 0

for domain in legitimate_domains:
    # 统一转小写,避免大小写影响统计
    domain_lower = domain.lower()
    # 生成该域名的字符级Bigrams
    domain_bigrams = ngrams(domain_lower, 2)
    for bg in domain_bigrams:
        bigram_counts[bg] += 1
        total_bigrams += 1

# 第二步:计算每个Bigram的概率(相对频率)
bigram_probs = {bg: count / total_bigrams for bg, count in bigram_counts.items()}

# 第三步:计算目标域名的Bigram Score
def get_bigram_score(domain):
    domain_lower = domain.lower()
    domain_bigrams = list(ngrams(domain_lower, 2))
    
    if not domain_bigrams:
        return 0.0
    
    # 对于不在合法语料库的Bigram,给一个极小概率(避免除以0)
    min_prob = 1e-6
    # 计算所有Bigram概率的平均值
    avg_prob = sum(bigram_probs.get(bg, min_prob) for bg in domain_bigrams) / len(domain_bigrams)
    return avg_prob

# 测试:正常域名 vs 疑似DGA域名
print("Bigram Score for 'example.com':", get_bigram_score("example.com"))
print("Bigram Score for 'xqkwtzvn.ru':", get_bigram_score("xqkwtzvn.ru"))
3. 计算域名的熵值

熵值用来衡量域名的字符随机性,DGA域名通常是算法随机生成的,熵值会远高于正常域名(正常域名一般有语义或品牌规律)。

示例代码:

import math
from collections import Counter

def calculate_domain_entropy(domain):
    domain_lower = domain.lower()
    total_chars = len(domain_lower)
    
    if total_chars == 0:
        return 0.0
    
    # 统计每个字符的出现次数
    char_counts = Counter(domain_lower)
    # 计算熵:H = -Σ(p(c) * log2(p(c))),其中p(c)是字符c的出现概率
    entropy = 0.0
    for count in char_counts.values():
        prob = count / total_chars
        entropy -= prob * math.log2(prob)
    
    return entropy

# 测试
print("Entropy for 'example.com':", calculate_domain_entropy("example.com"))
print("Entropy for 'xqkwtzvn.ru':", calculate_domain_entropy("xqkwtzvn.ru"))
整合特征用于分类

把Bigram Score、Trigram的类似统计特征(比如Trigram Score)、熵值组合成特征向量,就可以用简单的分类器(比如逻辑回归、朴素贝叶斯)训练DGA检测模型了。比如用sklearn的LogisticRegression:

from sklearn.linear_model import LogisticRegression
import numpy as np

# 假设你有标注好的数据集:(域名, 是否是DGA)
dataset = [
    ("example.com", 0), ("google.com", 0), ("facebook.com", 0),
    ("xqkwtzvn.ru", 1), ("zxcvbnm.top", 1), ("qwerasdf.net", 1)
]

# 提取特征
features = []
labels = []
for domain, label in dataset:
    bg_score = get_bigram_score(domain)
    entropy = calculate_domain_entropy(domain)
    # 可以再加Trigram Score等特征
    features.append([bg_score, entropy])
    labels.append(label)

# 训练模型
model = LogisticRegression()
model.fit(np.array(features), np.array(labels))

# 预测新域名
test_domain = "testdga123.com"
test_features = np.array([[get_bigram_score(test_domain), calculate_domain_entropy(test_domain)]])
print("预测结果(0=正常,1=DGA):", model.predict(test_features)[0])

内容的提问来源于stack exchange,提问作者SaiKiran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:34:25