如何提取域名的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
相关产品推荐
相关产品推荐

