MoreRSS

site iconyzqzss | 一座桥在水修改

RSS和博客研究,倡导 声冻计划、Save The Web Project(STWP)。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

yzqzss | 一座桥在水的 RSS 预览

CSSWAF: Browser Detection Using CSS (No JavaScript Needed)

2025-03-24 19:26:00

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>")

运行多用户 FreshRSS 实例的一些经验

2024-03-10 06:45:00

运行多用户 FreshRSS 实例的一些经验

一般项

常规的优化做做就可以了,另外 PHP 越新越好。

另外由于 FreshRSS 为每个用户创了两张数据库表(一张 article 一张 feed),所以数据库的 opened tables 会比较高,但也不用太关心这个指标,毕竟我们不可能有这么高的并发。

  • 推荐开启 WebSub。
  • 记得订阅 FreshRSS 的 GitHub Release
  • 将 ./p 作为网站根目录,不要把 FreshRSS 的根目录设为网站根目录

FreshRSS 升级

FreshRSS 升级时会把 ./data 复制一份到 ./data.bak ,这本身没啥问题。但是在我们的多用户实例上,./data/cache 轻轻松松就会积累起几万十几万个缓存文件,毕竟订阅源数量非常多。建议在升级前 cd ./data/cache && rm *.spc *.html 清理缓存。以免升级时给 ./data 打备份过久而 PHP 超时。

如果你有备份 crontab,记得排除 ./data/cache./data.bak

新用户默认订阅源

./opml.default.xml 默认是 FreshRSS 的 GitHub Release。

新用户默认配置

创一个 ./data/config-user.custom.php ,内容如下:

<?php
return array (
        'ttl_default' => 14400, # 最小 4h 自动刷新一次
        'dynamic_opml_ttl_default' => 43200, # dynamic opml 的刷新频率
);

可用参数见 config-user.default.php

让用户不能把更新频率改得太高

app/views/configure/archiving.phtml 里的几十分钟刷新一次的选项删掉,我是只留下了最快 4h 一次的选项。注意更新 FreshRSS 后要重新删掉。

禁用不活跃用户的自动更新

调整 ./data/config.phpmax_inactivity 值。

并行刷新订阅源优化

在 1.22.0 后,FreshRSS 给 app/actualize_script.php 加了进程互斥锁。这玩意极大拖慢了刷新一轮订阅源的效率。虽然单个刷新线程会5并发刷新 feed,但还是不够,而且一些 feed 死链,默认 20s 才会 timeout,又拖慢了全局刷新速度。

建议加下这个 patch,让你的 app/actualize_script.php 可以并行运行。

42c42
< $mutexTtl = 900; // seconds (refreshed before each new feed)
---
> $mutexTtl = 10; // seconds (refreshed before each new feed)
49c49,51
<       die();
---
>       // die();
> } else {
>       fclose($handle);
51d52
< fclose($handle);

不用担心并行刷新会导致冲突啥的,因为 feed 级别上也有锁,所以多个进程不会傻乎乎地同时去刷新同一个 feed 。

我是每 3 分钟起 9 个刷新进程,速度飕飕地。

for i in {1..9}; do sudo -u www-data /usr/bin/php /var/www/rss.othing.xyz/app/actualize_script.php & done

另外还可以启用 AutoTTL 插件,根据每个 feed 的实际更新间隔来自适应调整更新频率。不过你需要自己 patch 一下,把它改成系统级插件,而不是用户级插件。

管理插件

FershRSS 的插件手动安装和更新很麻烦。

为了方便,我做了个“FreshRSS 插件包管理器”——yzqzss/freshrss-ext-manager,妈妈再也不用担心我装的 FreshRSS 插件过时了。

备份

不推荐用 FreshRSS 自带的 cli 工具导出 sqlite dump,因为它会重排序 feed_id。另外,FreshRSS 的 Mysql/PostgreSQL 里存的 RSS 文章内容是压缩了的,导出成 sqlite dump 会解压,所以 dump 极大。

总结

经过一波优化下来,估计至少容纳 1k 用户应该没啥问题。

便利店的一元——回忆之8

2023-09-06 00:02:00

9/10 年前(具体时间记不清了)我还在读小学的时候,有次回家路上发现没带钱坐公交车,而同行的小伙伴们也正好没有多余的一块钱。于是我们合计着可以找公交站旁的一家便利店老板借借钱。

我也确实以“忘带钱要坐车”从老板手中借到一元。(那时候重庆还存在 1 元钱的公交车路线)

而后……可能出于害羞的心态??我不懂我自己,这一块钱一直到毕业也没还给便利店。那之后同行的同学其实有问过我有没有还,我撒谎说“还了”。此后我是路过就绕着这便利店走,不敢进去买东西,时间拖得越久,我越不敢进去还了。

是时候给这个故事画上个句号了,我打开地图,便利店还在,找到电话,添加微信。老板没同意好友申请,于是我在申请上留言说明了这件事。

“你不用记得,往前走越来越好就行”
“不用还了哈”
“有老人和孩子,生活中的这些普通的事早就记不住了”(由于微信只保留最近三条留言,这条我没截图到,但大概是这个意思)
  • 我:“嗯,谢谢。XX小学也改名了。”
  • 我:“祝好!”
“同祝安好”

#回忆 #小卖部没有还钱 8/n

轮胎作玩具,铁环的消失——回忆之6~7

2023-09-06 00:00:00

我在小区的废楼里找到一个摩托车轮胎。我把这个轮胎当作玩具,天天在小区里外滚上滚下,掌握了一番手刹、侧转等技巧。连找小伙伴玩我都带上这个轮胎。🌚

然后某天,因超速失去控制,这轮胎一头扎进沟里,Game Over,之后我就没轮胎玩了。🌚🌚

#回忆 #轮胎作为玩具 6/n


轮胎没了之后,我想玩玩正经的铁环。又过了好久,那时候淘宝开始普遍了,于是我让我爸上淘宝买了个。

说起来真悲催,到现在我在城市里也没看见哪个小孩/大人玩铁环。倒是有很多大人看到我在玩,就借过去滚两下过过瘾。

现在那铁环已经找不到了,不知道放哪儿了。

我觉得这项娱乐有复兴的潜力。🙈

#回忆 #铁环 7/n

盐——回忆之5

2023-09-05 23:58:30

我发现了个神奇的事情,把厨房里那种白色的粉洒在阳台的铁栏杆上,然后舌头舔,它有咸味的!

说起来我好像当时还给表姐分享了这个发现?以及,为什么当时我要把盐放在铁栏杆上再舔?

#回忆 #味道 5/n

FM广播、站起来及汶川地震——回忆之1~4

2023-09-05 23:57:00

我小时候,我爸用一根从阳台接到卧室里的电线当天线。那时候我们的 DVD 音响有收音机功能,我爸就用它来放广播。🙈
当时也会录些广播来着。

#回忆 #多媒体 1/n


刚进从幼儿园升到小学,在小学的第一次操场集会上(应该是领导在入学讲话吧),当时全部学生都是坐着的。我站了起来,旁边的人看见我一个人站了起来,于是也站了起来,于是所有人都站了起来。

这件事我自己记不清了,但是我小学同学的映像很深,所以我也就把它当作我自己的记忆吧。

#回忆 #小学 2/n


汶川地震发生后,重庆人也很担心重庆也会遭遇地震。很多人都从家里搬出来,在外面的空地上罢上地铺,睡外面,我们家也一样。

这段的记忆很不清晰了……我只记得我当时挺开心的,毕竟睡外面可是很新奇的!(现在只记得一个很模糊的画面,大概就是我躺在地上看夜晚的天?那时候我 5 岁。)

#回忆 #地震 3/n


汶川地震之后,到处都能看到爱心捐款箱。
有次在广场上看见有人在街头益唱筹善款,我爸妈给了我几块钱,让我走到唱歌那人前面,把钱投进筹款箱。
这段记忆为什么如此深刻?应该是当时太紧张了……

#回忆 #地震 4/n