CSSWAF: Browser Detection Using CSS (No JavaScript Needed)
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>")
如无声明,博客文章均以 CCO 协议发布-属于公共领域,可任意使用-但希望能署名