惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
D
Docker
Stack Overflow Blog
Stack Overflow Blog
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
H
Help Net Security
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
L
LangChain Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
SegmentFault 最新的问题
博客园 - 司徒正美
C
Check Point Blog
B
Blog
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
F
Fortinet All Blogs
美团技术团队
D
DataBreaches.Net

yzqzss|一座桥在水上’s Blog

运行多用户 FreshRSS 实例的一些经验 便利店的一元——回忆之8 轮胎作玩具,铁环的消失——回忆之6~7 盐——回忆之5 FM广播、站起来及汶川地震——回忆之1~4 部分录音数据再次丢失 「农村合作基金会」——改革开放时期的“县乡银行” 别人说俺是英雄——记小时候一次造永动机的尝试 中文独立博客的年化“腐烂率”——8%
CSSWAF: Browser Detection Using CSS (No JavaScript Needed)
2025-03-24 · via yzqzss|一座桥在水上’s Blog

Inspired by Anubis last week, I came up with an idea to detect if a client is a browser using CSS animations and image lazy loading. I spent a few hours writing a simple PoC, and it works!

How it works?

CSSWAF places random hidden empty.gif images in CSS animation progress, allowing the browser to play these images one by one in order.

...
<style>
@keyframes csswaf-load {
  ` + func(expectedSequence []string) string {
        lines := []string{}
        for i, img := range expectedSequence {
            f := float64(i) / float64(len(expectedSequence))
            lines = append(lines, strconv.Itoa(int(f*100))+`% { content: url('/_csswaf/img/`+img+`?sid=`+sessionID+`'); }`)
        }
        lines = shuffle(lines)
        return strings.Join(lines, "\n")
    }(expectedSequence) + `
}
.csswaf-hidden {
width: 1px;
height: 1px;
position: absolute;
top: 0px;
left: 0px;
animation: csswaf-load ` + strconv.FormatFloat(cssAnimationTS, 'f', -1, 64) + `s linear infinite;
}
</style>
...
<div class="csswaf-hidden"></div>

The backend measures the loading order. If the loading order is correct, it passes the request to the target server. Otherwise, 🙅.

...
// Check if sequence matches expected sequence
expectedSeqTTL := st.expected.Get(sessionID)
var expectedSeq []string
if expectedSeqTTL != nil {
    expectedSeq = expectedSeqTTL.Value()
}
if expectedSeq != nil && len(sequence) == len(expectedSeq) {
    match := true
    for i := range sequence {
        if (sequence)[i] != (expectedSeq)[i] {
            match = false
            break
        }
    }
    st.validated.Set(sessionID, match, ttlcache.DefaultTTL)
...

HoneyPot

CSSWAF places some honeypot empty.gif files in HTML <img> tags but instructs the browser not to load them. If someone loads the honeypot GIFs, 🙅.

lines = append(lines, `<img src="/_csswaf/img/`+img+`?sid=`+sessionID+`" style="width: 0px; height: 0px; position: absolute; top: -9999px; left: -9999px;" loading="lazy">`)

CSSWAF also places some unvisible <a> tags in HTML, if someone clicks the honeypot links, 🙅.

.honeya {
    display: none;
    width: 0px;
    height: 0px;
    position: absolute;
    top: -9898px;
    left: -9898px;
}

lines = append(lines, "<a href='/_csswaf/img/"+img+"?sid="+sessionID+"' class='honeya'>View Content</a>")