如何用爬虫、机器学习识别方式屏蔽恶意广告
·
这是一个非常硬核的系统工程题目。要构建一个能够识别“恶意广告”(Malvertising)的系统,不能仅靠简单的黑名单(AdBlock模式),必须结合主动诱捕(Active Crawling)、视觉分析(Computer Vision)和代码行为分析。
恶意广告通常具有以下高阶特征,传统手段难以屏蔽:
- Cloaking(伪装):针对爬虫展示正常内容,针对真实用户展示恶意载荷。
- DOM Obfuscation(混淆):频繁变换 HTML 结构和 JS 变量名。
- Social Engineering UI(社会工程学 UI):伪装成系统弹窗、关闭按钮或虚假杀毒软件界面。
一、 整体系统架构设计
这是一个典型的“多模态”检测系统。我们需要同时处理视觉数据(截图)、文本数据(JS代码/URL)和网络行为数据(跳转链)。
二、 核心模块一:抗检测的“诱捕”爬虫 (Anti-Cloaking Crawler)
恶意广告商会通过指纹识别(Canvas Fingerprinting、Webdriver检测)来屏蔽爬虫。我们需要使用 Playwright 配合 stealth 插件,并注入“鼠标抖动”等人类行为。
关键代码逻辑:
import asyncio
from playwright.async_api import async_playwright
async def capture_malvertising(url):
async with async_playwright() as p:
# 1. 启动抗检测浏览器上下文
browser = await p.chromium.launch(headless=False) # 必须有头模式以规避部分检测
context = await browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
viewport={'width': 1920, 'height': 1080}
)
# 2. 注入反检测脚本 (Stealth)
await context.add_init_script(path="stealth.min.js")
page = await context.new_page()
# 3. 监听网络请求链 (捕获重定向)
redirect_chain = []
page.on("request", lambda request: redirect_chain.append(request.url))
try:
await page.goto(url, wait_until="networkidle")
# 4. 模拟人类行为:随机滚动鼠标,触发懒加载广告
await page.mouse.move(100, 100)
await page.evaluate("window.scrollTo(0, document.body.scrollHeight/2)")
# 5. 定位 iframe 广告并截图
frames = page.frames
for i, frame in enumerate(frames):
# 简单的启发式规则:过滤掉太小的像素点,保留像广告的区域
box = await frame.evaluate("() => document.body.getBoundingClientRect()")
if box['width'] > 50 and box['height'] > 50:
# 保存截图用于视觉分析
await frame.screenshot(path=f"ad_frame_{i}.png")
# 保存页面源码用于代码分析
content = await frame.content()
with open(f"ad_source_{i}.html", "w") as f:
f.write(content)
except Exception as e:
print(f"Error: {e}")
finally:
await browser.close()
return redirect_chain
# 运行采集
# asyncio.run(capture_malvertising("http://high-risk-site.com"))
三、 核心模块二:特征工程深度解析
除了截图,最核心的是识别JavaScript 的恶意程度。恶意广告代码通常经过高度混淆(Obfuscation)。我们可以通过计算**信息熵(Shannon Entropy)**来量化代码的混乱程度。
代码特征提取逻辑:
import math
import re
from collections import Counter
def calculate_entropy(text):
"""计算字符串的信息熵。恶意混淆代码通常熵值很高"""
if not text: return 0
entropy = 0
length = len(text)
counts = Counter(text)
for count in counts.values():
probability = count / length
entropy -= probability * math.log(probability, 2)
return entropy
def extract_code_features(js_code):
features = {}
# 1. 信息熵特征 (混淆检测)
features['entropy'] = calculate_entropy(js_code)
# 2. 危险函数检测 (正则匹配)
# 恶意广告常用 eval, document.write 动态生成内容
dangerous_patterns = [
r'eval\(',
r'document\.write\(',
r'window\.location',
r'unescape\(',
r'atob\('
]
features['suspicious_func_count'] = sum(1 for p in dangerous_patterns if re.search(p, js_code))
# 3. 字符串特征
# 查找超长字符串(通常是加密的 Payload)
longest_string = max(len(s) for s in re.findall(r'"([^"]*)"', js_code)) if re.findall(r'"([^"]*)"', js_code) else 0
features['max_str_len'] = longest_string
# 4. 脚本长度
features['code_length'] = len(js_code)
return features
# 示例:一段混淆代码的熵会很高,普通代码熵较低
# print(extract_code_features("eval(function(p,a,c,k,e,d)..."))
四、 核心模块三:视觉识别模型 (Fake UI Detection)
这是对抗社会工程学广告(如假装是一个系统弹窗)的关键。我们需要训练一个 CNN 模型。
-
数据集构建:
- 正样本(恶意):带有 “Download”, “Scan Now”, “Close”, “System Warning” 样式的广告图。
- 负样本(正常):普通的电商广告、品牌展示。
-
模型架构思路:使用迁移学习(Transfer Learning),基于 EfficientNet 进行微调,因为它在速度和精度上平衡较好,适合浏览器端的推理。
PyTorch 模型定义示例:
import torch
import torch.nn as nn
from torchvision import models
class MaliciousAdNet(nn.Module):
def __init__(self):
super(MaliciousAdNet, self).__init__()
# 使用预训练的 ResNet18 或 EfficientNet
self.base_model = models.resnet18(pretrained=True)
# 冻结浅层参数,只训练分类头
for param in self.base_model.parameters():
param.requires_grad = False
# 替换全连接层
num_ftrs = self.base_model.fc.in_features
self.base_model.fc = nn.Sequential(
nn.Linear(num_ftrs, 128),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(128, 2) # 二分类:良性 vs 恶意
)
def forward(self, x):
return self.base_model(x)
# 训练时,重点关注 False Positive(误报),因为屏蔽正常广告会影响用户体验。
五、 最终部署:融合推理
在实际应用中(例如浏览器插件网关),我们采用流水线过滤机制以保证性能:
- Level 1 (毫秒级):Bloom Filter 黑名单。检查 URL 是否在已知的恶意域名库中。
- Level 2 (毫秒级):轻量级代码分析。如果 JS 代码熵值过高(>5.5)且包含
eval,直接标记风险。 - Level 3 (秒级):视觉推理。如果前两步不确定,则在后台对渲染出的 iframe 进行截图,送入 CNN 模型判断。
融合判定伪代码:
def predict_ad_safety(url_features, code_features, image_features):
# 权重分配:代码特征通常比视觉特征更可靠
risk_score = (
0.3 * model_visual.predict(image_features) +
0.5 * model_code.predict(code_features) +
0.2 * model_network.predict(url_features)
)
if risk_score > 0.85:
return "BLOCK"
elif risk_score > 0.6:
return "SUSPICIOUS_SANDBOX" # 放入沙箱隔离运行
else:
return "ALLOW"
总结
要真正屏蔽恶意广告,不能只盯着“广告”本身,而是要识别“攻击行为”。
- 爬虫负责撕开伪装(Anti-Cloaking)。
- OCR/CNN负责识破视觉欺诈(Fake UI)。
- NLP/熵分析负责检测底层代码的恶意载荷(Obfuscated Payload)。
这套组合拳打下来,能有效拦截那些能够绕过传统 AdBlock 规则库的 0-day 恶意广告。
更多推荐

所有评论(0)