treehollow / treehollow-backend

T大树洞 的Golang后端
https://thuhole.com/
GNU Affero General Public License v3.0
167 stars 47 forks source link

关于树洞匿名性的讨论 #11

Closed xjgwbo closed 4 years ago

xjgwbo commented 4 years ago

根据树洞里的公告:

出于对用户隐私的保护与尊重,后台不会记录任何您的个人信息,单向加密的技术手段确保了没有人可以从一条树洞号查出发送树洞的邮箱。同时,T大树洞不会向用户收取任何费用,也没有植入任何的商业广告。

我对于这个表述产生很大的质疑。根据后端 https://github.com/thuhole/thuhole-go-backend/blob/master/src/db.go 可见后端存储发帖人信息的逻辑是根据 email_hash 字段:

    doPostIns, err = db.Prepare("INSERT INTO posts (email_hash, text, timestamp, tag, type ,file_path, likenum, replynum) VALUES ((SELECT email_hash FROM user_info WHERE token=?), ?, ?, ?, ?, ?, 0, 0)")
    fatalErrorHandle(&err, "error preparing posts sql query")

根据 email_hash 属于 user_info 表可知,每一个用户的 email_hash 是唯一的。因此开发者 可以非常容易地通过查阅 postsemail_hash 表了解到发帖人信息,T大树洞完全是单向匿名的,管理员可以查看所有树洞的真实信息。

并且,这一hash的构造过于简单,根据 utils.go:

func hashEmail(user string) string {
    h := sha256.New()
    h.Write([]byte(user))
    return hex.EncodeToString(h.Sum(nil))
}

在用户量小到可以忽略的条件下(甚至所有学生都注册的条件下,也不过是几万个email)这个hash形同虚设,对于开发者想要重新生成所有的邮箱对应的hash只需要几毫秒,因此树洞发帖人可以轻易查询。

我们对于树洞公告中做出的 ”具有迷惑性“ 的陈述鼓励用户自由发帖,和这显著没有考虑用户匿名性的代码设计产生极大的怀疑。

希望开发者公开回应我们的质疑,赢得用户的信任。

thuhole commented 4 years ago

我们接受您的质疑。

实际上,这个漏洞我们也意识到了,brute force是一种可以快速破解此单向加密的方式。但由于开发时间所限,我们暂时采用了这样的方案。

因此我们计划,在未来,将匿名性的保证从服务器端移动到客户端(也就是网页代码),对每条树洞和评论生成非对称密钥存储在客户端内。如果您对这个未来树洞匿名性方案的设计感兴趣,欢迎继续讨论。 ################################################################ 更新:#25 已变更hash函数

thuhole commented 4 years ago

将匿名性的保证移动到客户端之后,主要技术问题在于,多客户端之间的数据迁移较为难办。

xjgwbo commented 4 years ago

感谢您及时的回复。

我们担忧的是在这一机制健全之前,对于用户做出的有失准确性的承诺。对于匿名社区,我们很难对于后端是否是 “可信的” 给予全部的信任。P大树洞创始之初曾经也出现过信息泄露的情况,而P大树洞因为采用AES-256加密,拖库后依然得以保存了用户的匿名。您现在构建的架构具有极大的风险,任何掌握数据库的人可以轻松了解到所有人发送的所有信息,这与您的公告背道而驰。

建议参考P大树洞的信息保护机制,北大青年的报道曾经给出过一些解释,不知具体实现方式如何,但应该是将密钥在后端隔离存储,至少不会轻松逆向hash。现在的机制真的过于简单。

树洞的信息由两个部分组成:已加密的数据库,以及用于解密的密钥。树洞的编号和内容可以从数据库中读取,但发贴人的学号经过加密处理,破解难度很高。出于保护学生安全和隐私的考量,数据库和密钥严格分开保管,即使是开发者,在进入Helper团队时也只能选择拥有其中一个。也就是说,解密的过程需要多方协作,任何一个人都不可能擅自获得发帖人的实名信息。

thuhole commented 4 years ago

现在的机制简单是因为树洞仍在初期阶段,管理人员人数也较少。

您的建议我们会认真考虑,持续优化!

thuhole commented 4 years ago

对于目前的数据库结构,有一条解决途径是把email_hash的值从sha256(email)转变为sha256(secret+sha256(email)),其中secret是只能在内存中存在的加密变量,您觉得这样是否合理?

thuhole commented 4 years ago

另外一个问题是,完全匿名的设计是否合理?如果用户发表违法内容、强烈自杀倾向内容,是否有必要允许检察机关和公共安全机关解密数据?

panda2134 commented 4 years ago

对于目前的数据库结构,有一条解决途径是把email_hash的值从sha256(email)转变为sha256(secret+sha256(email)),其中secret是只能在内存中存在的加密变量,您觉得这样是否合理?

util.go中来看,甚至没有加盐,匿名性有较大的问题,因为本来清华邮箱就不多,格式又固定,很容易撞出来原文。

我的建议是把盐加密,且解密的明文盐和加密使用的key都只存在内存中,然后把第一次sha256的结果和盐拼接后再sha256,这样也可以较为方便的迁移。

我不懂密码学,也不知道这样有无潜在风险,但是看上去比当前方案靠谱多了。

panda2134 commented 4 years ago

另外一个问题是,完全匿名的设计是否合理?如果用户发表违法内容、强烈自杀倾向内容,是否有必要允许检察机关和公共安全机关解密数据?

如果不采用完全匿名的设计,就很难保证被攻击后用户匿名性得到保证,相信这也会降低用户的热情。

不如短期内还是采用社区自行维护的方式。毕竟错的常常不是匿名和加密的工具,而是使用工具的人。

panda2134 commented 4 years ago

对于目前的数据库结构,有一条解决途径是把email_hash的值从sha256(email)转变为sha256(secret+sha256(email)),其中secret是只能在内存中存在的加密变量,您觉得这样是否合理?

util.go中来看,甚至没有加盐,匿名性有较大的问题,因为本来清华邮箱就不多,格式又固定,很容易撞出来原文。

我的建议是把盐加密,且解密的明文盐和加密使用的key都只存在内存中,然后把第一次sha256的结果和盐拼接后再sha256,这样也可以较为方便的迁移。

我不懂密码学,也不知道这样有无潜在风险,但是看上去比当前方案靠谱多了。

如果把第二次sha256换成一个对称加密算法,然后定期进行key rotation,安全性应该会更高。

thuhole commented 4 years ago

我觉得这件事可能需要专业人士指导,还好目前用户还不是很多

panda2134 commented 4 years ago

我觉得这件事可能需要专业人士指导,还好目前用户还不是很多

邮箱加盐存储是基础操作,我觉得这个应该不会有太大难度?当然还是咨询懂密码学的同学为好。建议在树洞置顶找人。

在此之前,应该出于对用户负责的态度,在树洞上说明现在平台的测试性质。

thuhole commented 4 years ago

@panda2134 请您谅解自由软件开发不易。。。

panda2134 commented 4 years ago

@panda2134 请您谅解自由软件开发不易。。。

完全理解个人开发者的困难,也明白GPLv3中说明了Without warranty,但是大家都是希望清华树洞能做的更好。 这几天如果有时间我尽量来交一个pr吧。

thuhole commented 4 years ago

@panda2134 谢谢您的理解!PR的话。可能一是需要把现有代码改了,二还要做一个migration代码。提前还要做数据库备份。这应该是个大更新了,我估计会把fallback server的维护提示信息做好一点。

顺便,这个repo的License是“All Right Reserved”。

thuhole commented 4 years ago

首先我觉得,需要明确隐私安全的目标要到多安全。 比如: Level 1:如果服务器被SQL Injection,无法查看发帖人 Level 2:如果服务器只有root权限才能查看发帖人 Level 3:即使服务器root权限被攻破,仍然无法查看发帖人

我想,第一节阶段先从Level 1提升到Level 2吧。Level 3会有很多对用户不友好的事情,可能以后做了Android和iOS客户端之后才会方便部署。

xjgwbo commented 4 years ago

Level 2 是基本的。Level 3 完全实现较难,建议通过加盐+多iteration(比如PBKDF2)来极大的减少brute force的效率。

私认为用hash function在这里是不合适的。你还要兼顾到准确识别reply的归属用户的问题,因此加密必须部分可逆。因此,正经的AES加密保护发帖人身份是更合适的做法,然后通过给用户分配多个临时identifier来控制reply归属的识别。identifier可以存在内存里(比如memcached),getcomment 的时候调用一个和memcache连接的daemon来解析身份。

根据P大的描述,我猜应该是AES加密发帖人信息,然后密钥解析的接口是单独控制的,否则无法实现 “开发人员只能选择数据库和密钥二者之一” 的设定。至少T大的安全标准不应当低于Level 2。

此外,后端即使公开源码(注意是 ”公开“ 而非 ”开源“,因为您没有后端FOSS license)也是不可信的,我们无从得知您是否在后端中真正使用了您公开版本的代码。

OmmyZhang commented 4 years ago

这和“Android和iOS客户端”没有太大关系吧 网页/PWA本身就可以本地持久化存储数据。

thuhole commented 4 years ago

@xjgwbo 首先,如果brute force效率低,那么土豆服务器肯定撑不住,这个tradeoff不太好把握。 其次,hash function和AES不矛盾,可以都用。 临时identifier主要的问题是目前服务还处于初级阶段,可能会经常宕机,仅在内存里存储不合理。 我们目前的管理模式和P大差距很大,所以我想不能直接借鉴。 最后,我想说,没有任何东西是可信的。怀疑论不可取。你觉得不可信可以不注册。

panda2134 commented 4 years ago

image

在树洞访问页面已经标明是gplv3,似与此处矛盾。

thuhole commented 4 years ago

@panda2134 前端和后端不一样

panda2134 commented 4 years ago

Level 2 是基本的。Level 3 完全实现较难,建议通过加盐+多iteration(比如PBKDF2)来极大的减少brute force的效率。

私认为用hash function在这里是不合适的。你还要兼顾到准确识别reply的归属用户的问题,因此加密必须部分可逆。因此,正经的AES加密保护发帖人身份是更合适的做法,然后通过给用户分配多个临时identifier来控制reply归属的识别。identifier可以存在内存里(比如memcached),getcomment 的时候调用一个和memcache连接的daemon来解析身份。

根据P大的描述,我猜应该是AES加密发帖人信息,然后密钥解析的接口是单独控制的,否则无法实现 “开发人员只能选择数据库和密钥二者之一” 的设定。至少T大的安全标准不应当低于Level 2。

此外,后端即使公开源码(注意是 ”公开“ 而非 ”开源“,因为您没有后端FOSS license)也是不可信的,我们无从得知您是否在后端中真正使用了您公开版本的代码。

同意。理解作者不愿意公开身份,但是服务器运行如果能更公开一点(如:开发组内人数多一些)会更好。如果all rights reserved,无疑会打击开发者贡献代码的积极性。这无疑是作者的选择自由,但是我个人还是更希望能采取一个较为permissive的开源协议。

edited on 2020/06/21 22:36 utf+8

thuhole commented 4 years ago

@panda2134 同意。LICENSE已更新为GPL v3

panda2134 commented 4 years ago

是否可以考虑参考v2ray/v2ray-core的开发组模式?

thuhole commented 4 years ago

是否可以考虑参考v2ray/v2ray-core的开发组模式?

您详细讲解一下这是什么样的模式?

panda2134 commented 4 years ago
  1. 代码开源,便于任何人发PR/做audit
  2. 开发组人员之间可以互相匿名,也可以保持实名;关于新功能的讨论应该公开;任何安全相关问题,组内成员都应该向全组上报。
  3. 采用公用PGP Key汇报安全问题,亦可以用protonmail

又:考虑到树洞的社交性质,即使网站不在中国大陆境内,也应该设置和司法部门合作的通道(比如专门的邮箱),防止恶性事件的发生。

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On 2020年6月21日SundayPM10点38分, thuhole notifications@github.com wrote:

是否可以考虑参考v2ray/v2ray-core的开发组模式?

您详细讲解一下这是什么样的模式?

You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub, or unsubscribe.[https://github.com/notifications/beacon/ABXHMIE2UOLHGST2V3SB7Y3RXYLNZA5CNFSM4ODVBRQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOE2JILKA.gif]

thuhole commented 4 years ago

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256

@panda2134 这样的开发模式听起来很可取。不过后端可信这件事上,我觉得可能初期还是只有独裁效率。等运营模式稳定了之后再讨论后端可信。 -----BEGIN PGP SIGNATURE----- Version: OpenPGP.js v2.3.2 Comment: http://openpgpjs.org

wsBcBAEBCAAQBQJe73PmCRB7id61akIDUAAAnGQH/0txq02da41BsdwsS482 1WjAvciljkKSo1Uj7MwcBxZdKi1J4KwJ6Hset+t22rhnMJVZPA749zAvAQAA yKgmkRr85Q19Wb1YLv0mxbT/i7rrmqkd2VoUMvrfzv8udBRlWpyj7FK04UwX IO796KH2uOe3xlCF3x4uG22490Jb/COkJVuhFyJOfHLmsPla7dx2iTHEfhyA fDvgK2nn03OPOYRCSAClt7rg460iC2CHKT7cY6Dp11UcgsgZ7cGCqVkZXUpY r79FeNcQ82QXeOvcXx+TfBjaSxI88WaTW4tB2LOSH+5vqbAD1YV5TWJsSzN+ JHI4Z6L+b5j2FmpDfWw90bU= =BXDf -----END PGP SIGNATURE----- -----BEGIN PGP PUBLIC KEY BLOCK----- Version: OpenPGP.js v2.3.2 Comment: http://openpgpjs.org

xsBNBF7vc94BCADARi5/7Y1T2tAfDMXGp40fkxiFp6s9cGNDLaE0JILgM38U jiOGRf/4jNzc+9I6skpcwZV0lM07SotGWLZSasVnamJK5ZdvdJWq9aQR/GMu QVs7VTWk5EuDvbzJ/PiCz5fP4xA6GAQsMbIrDSxZBoQ4mONwv8n+ovpHXGGQ AslRdyk/D7iAWjTk2+wglmqt0gGvpWHOz12vc5bqT8GqYAw1axUQ3V63LFCK CES2lMExbOAU9+RchI71SCATj+bNPIj9mr7Ff5mKfPpP0yF/vanjJA1sUaeH 8yR8TUkr+6DZwcQ8z/ujSfcv6YcH5ZOI7TCO8186XMY546l8bvlZNpGHABEB AAHNCnRodWhvbGUgPD7CwHUEEAEIACkFAl7vc94GCwkHCAMCCRB7id61akID UAQVCAIKAxYCAQIZAQIbAwIeAQAAcFcIALI/z/ySboQPz3/U//umeB65PHWH FFwBB4oRl7YndtrmMEUhboXO7Z+3qQ8dtqtjRCeUQE4MAxYkIIKxbODHzLzb 785sZE0tjmsSw+cX6KMxcGy4Y39cpeYuqLsLOnQAxZsAHQw03jocTJD8COWD +w5sOVF6zSmOql1dcPRmGMQGsOLnMsiQSu238E2bMm23fQAoGUms8F2ygGVS Nf7Q+2EiybwqruJeidgONSQ1pXlPCex7XKYNVOmjNhFVAb8QO5xyPViUMbPQ rTJWjye9RtyK0yoYoNGhO//0ogfAcnrzADRi+LmAicVCOa4sHE6SOyuX4HKq 15iUzGlMz95bez3OwE0EXu9z3gEIAK5TCA2vn6s0UnctvzSJEMpqjX7u5N3q FMcZ1CQoTtDTVs6WFaWny5mgvps5+ZKXRxP4gNswSWU1R0jZQjLE3/uBru/U Na/F5c2Ai6sFfXAh2tYCq0S6YQwe8asyCwRH57NQ2cne+9I3J1tgbEYytZ0H M7F7gPu/tEbtVIsbo+nYTPbGgdYd7R6gqckwTojXVL4Gq7dHzL/tQg+v6V8+ bm+zdHZ49YlJvAY8arx1ohzwUL80MDwfkCDs4UiAiHgY/yIKBLOjfVSSuM2p buLIK3WaGkHgdnte0b8QJ17Ol5nnJOD87jTLrDRqgKFjHAZnyI5cn1CHYuFK u3u3w5HRCqsAEQEAAcLAXwQYAQgAEwUCXu9z3gkQe4netWpCA1ACGwwAAP/s B/wIIkSPoY161tkjuoLTOlGGJBxEWR/DAgkrUBPh43py9UCYWF45XqGsLPk9 CkTYopNsWuHMmLukf/zFJ7z0mczlXo47dLeg85Xb5CgJ/RfHUx7MyCpdOFhX ZbnG24UIhEBHxnY8JrsOfofkGoED75MoT5HaLvDmiulfS632kJc4vkjZDRrm SZXh2hMwQW+9Ba+HH7o98nV40aColjzHJuQ6QcCpL2BNqX1t32Bn9lN6ogqw uwLm7pVp/katZ6SbZSYOd6apaTyrYiZiSEhCAYdBssy95S942eNaZrOkp6vm byl4lY1mIif4Oiru0Nnhh1kUJTwK1Cs3WkfrAPuD61tk =NLz0 -----END PGP PUBLIC KEY BLOCK-----

panda2134 commented 4 years ago

个人认为这个issue得提上日程? 毕竟把sha256换掉/加密也不是很难的事情

既然sha256和明文差不多的话,直接给sha256上个加密应该就可以保证仅管理员查看了,这就是上面说的lv2

panda2134 commented 4 years ago

建议在树洞置顶找有相关领域经验的开发者来实现加密功能

panda2134 commented 4 years ago

还有关于匿名,听说学校相关部门已经盯上这个项目了,所以说一个比较靠谱的方案是找到依托的组织实行正规化(类似隔壁的方案?),就是不知道学校的态度有没有隔壁那么包容。。。

仅代表个人观点。

thuhole commented 4 years ago

@panda2134 #25

Alan-Liang commented 4 years ago

我昨天晚上想了好几个办法,都是一半 level 2 一半 level 3 的,最简单的一个是这样:

先生成一个用来查询是谁的密钥对 S,在配置文件里写进去 S 的公钥。注册的时候需要提供一个密码,用 E ← HKDF-Extract('thuhole', email + ':' + password) 在浏览器里完成,把公钥和 email 发给服务器(密码不发),私钥留着用来签名树洞消息;服务器收到之后用 S 加密邮箱和 E 的公钥这个 map 存到数据库,并且明文保存 E 的公钥(用来验证树洞里的匿名身份);登录的时候用同样的方法重新生成 E,签一个 challenge 给服务器,就算登录成功;发消息的时候只要验签即可;查身份的时候用 S 的私钥解密一遍存的所有 mapping,对一下这个 E 对应哪个邮箱即可。

为什么说是一半 level 2 一半 level 3 呢?因为 Eve 拿到 root 之后最多也就能把新注册的人的身份拿到,已有消息的身份还是没法得到。(当然,建立在 S 私钥不泄漏的前提下,这个私钥永远不应该在服务器的任何地方出现。)

优点:这个「一半」如果只是一次性攻击可以近似认为就是 level 3;Eve 需要长期潜伏在 root 里才能拿到身份。

缺点:没法找回密码,没法迁移已有消息(我不知道有多少已有消息,不是贵校的人😂)

一个建议:这个 S 的私钥可以用 Shamir's t-out-of-n 分成若干份,保存在不同的人(其中可以有校方的人)手里。

还有一个办法,可以全 level 3 但是如果有意攻击能造成谁都查不出来身份……就先不说了。

thuhole commented 4 years ago

根据《中华人民共和国网络安全法》 第二十一条

(三)采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月;

第二十四条 网络运营者为用户办理网络接入、域名注册服务,办理固定电话、移动电话等入网手续,或者为用户提供信息发布、即时通讯等服务,在与用户签订协议或者确认提供服务时,应当要求用户提供真实身份信息。用户不提供真实身份信息的,网络运营者不得为其提供相关服务。

第六十一条 网络运营者违反本法第二十四条第一款规定,未要求用户提供真实身份信息,或者对不提供真实身份信息的用户提供相关服务的,由有关主管部门责令改正;拒不改正或者情节严重的,处五万元以上五十万元以下罚款,并可以由有关主管部门责令暂停相关业务、停业整顿、关闭网站、吊销相关业务许可证或者吊销营业执照,对直接负责的主管人员和其他直接责任人员处一万元以上十万元以下罚款。

关闭此Issue, 由#25 取代