小书签安全注意事项、CSRF、散列密钥

发布于 2024-10-19 16:01:18 字数 1274 浏览 3 评论 0原文

我的小书签可以从任何网站调用,并且基本上允许用户从远处将一行插入到他的收藏中 - 如果他已登录。

现在我想为我的网站启用 CSRF 保护,因为小书签基本上是非伪造的跨站点请求,我想如何区分它和伪造的。
这不是一个高安全性的环境,但我对原理也很感兴趣。

我以为我有办法解决这个问题,但后来意识到它有很多问题。

最初的想法

  • 是生成一个随机密钥,该密钥包含在小书签链接中。密钥的哈希值保存在数据库中。随机密钥仅允许访问插入此集合的权限,不能在其他任何地方使用。
  • 小书签从我的服务器加载更长的脚本,因此我可以通过这种方式提供 CSRF 预防令牌,
  • 要求用户登录

问题

  • 如果我有小书签密钥,我是否需要反 CSRF 令牌?
  • 如果用户在恶意网站上单击他的书签,有什么方法可以保护书签密钥?
  • 我不希望用户名和密码存储在书签链接中,因为任何有权访问计算机的人都会获得密码,所以我决定使用随机密钥。
    • 但是如果我只存储哈希值,我就无法两次生成相同的小书签链接,因此当用户想要在另一浏览器/计算机中使用小书签时,他必须繁琐地从旧浏览器/计算机中导入链接或中断对旧浏览器/计算机的支持.
    • 但我不应该存储明文密钥,因为获得数据库访问权限的人可以使用此密钥将行插入不属于他的帐户。
    • 可能的解决方案我可以要求用户在创建小书签时提供密码,并多次对密码进行哈希处理,然后将该哈希值放入 URL 中,然后将哈希值放入我的数据库的哈希值。但当然这会带来更严重的安全漏洞。
      • 我可以用“母亲的婚前姓名”之类的内容来代替
      • 由于随机盐,我无法使用 bcrypt 进行哈希,对吧?什么哈希函数是正确的?或者你会否决整个想法?
  • 如果我留下小书签密钥,恶意网站可以简单地嵌入小书签并从中提取有效的 CSRF 令牌,对吧?

更好的想法?或者没有 F 就不能实现企业社会责任吗?


编辑,指定用例

我根本没有想到的一件事是按照 Sripathi Krishnan 的建议使用 iframe。

我没有指定我的用例,所以是的,iframe 是上述问题的有效解决方案 问题。

然而,实际上我的小书签目前确实在运行时与网站进行了一些基本交互(这意味着表单已经存在,用户可以在网站 DOM 中更改他的选择,这应该更改表单)。我准备在我的用例中放弃此功能,如果事实证明,没有相当安全的方法来区分伪造和非伪造的跨站点请求 - 但我仍然对理论层面感兴趣。

My bookmarklet can be called from any website and basically allows the user to insert a row into his collection from afar - if he is logged in.

Now I want to enable CSRF protection for my site and since a bookmarklet is basically non-forged cross site request, I thought about how I could tell it apart from forged ones.
It's not a high-security environment, but I'm also interested in principle.

I thought I had a way to do it figured out, but then realised that it had problems galore.

Original idea

  • generate a random key that is included in the bookmarklet-link. The key's hash is saved in the database. The random key allows access ONLY to the privilege of insertion into this collection and can't be used anywhere else.
  • the bookmarklet loads a longer script from my server, so I could supply a CSRF prevention token this way
  • require the user to be logged in

Problems

  • If I have the bookmarklet key, do I need counter-CSRF tokens?
  • Is there any way that I could protect the bookmarklet key if the user clicks his bookmarklet on a malicious website?
  • I don't want username and password to be stored in the bookmarklet link, because anybody who has access to the computer would get the password as well then, so I decided on the random key.
    • but if I store only the hash, I cannot generate the same bookmarklet link twice, so when the user wants a bookmarklet in another browser/computer he tediously has to import the link from the old one or break support for the old one.
    • but I shouldn't store the cleartext key, because someone who gains access to the database could use this key to insert rows into accounts that don't belong to him.
    • Possible solution I could ask the user to provide his password anytime he creates the bookmarklet and hash the password many times and put that hash in the URL and put the hash of that hash my database. But of course this opens much worse security holes.
      • I could do this with something like "Mother's maiden name" instead
      • I cannot use bcrypt for hashing because of the random salt, right? What hash function would be right? Or would you dismiss the whole idea?
  • If I leave the bookmarklet key out, a malicious website could simply embed the bookmarklet and extract a valid CSRF token from it, right?

Better ideas? Or can't you have CSR without the F?


Edit, specified use case

One thing I simply didn't think about, is the usage of an iframe as suggested by Sripathi Krishnan.

I had not specified my use case, so yes, an iframe is a valid solution to the aforementioned
problem.

However, actually my bookmarklet at the moment does do some basic interaction with the website at runtime (meaning the form is there already and the user can change his selection in the website DOM which should change the form). I'm ready to dismiss this functionality for my use case, if it turns out, there's no reasonably-secure way to tell apart forged from non-forged cross-site requests - but I'm still interested on a theoretical level.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独守阴晴ぅ圆缺 2024-10-26 16:01:18

如果不消除伪造部分,就无法发出跨站点请求。但对于您的用例,我认为您不需要跨站点请求。

假设您的服务允许用户为他想要的任何页面添加书签。小书签的工作是将 {url, title} 保存到数据库中。同时,您希望防止恶意网站自动保存登录用户的 url。

我将采取以下措施来解决此问题 -

  1. 在您的域上创建一个具有标准 html 表单并具有常规 CSRF 保护的页面。该页面接受参数 {url, pagetitle},但仅当用户明确单击“保存”按钮时才会保存此元组。
  2. 小书签的工作是加载 iframe
  3. 一旦 iframe 加载,它就是一个正常的同源请求

这或多或少是 Google 阅读器作为其小书签的一部分所做的事情。这是其书签的代码 - 请注意它没有任何标记


javascript:
var b=document.body;
var GR________bookmarklet_domain='http://www.google.com';
if(b&&!document.xmlVersion) {
  void(z=document.createElement('script'));
  void(z.src='http://www.google.com/reader/ui/link-bookmarklet.js');
  void(b.appendChild(z));
 }
 else{}

编辑:
您仍然可以支持与 iframe 方法的交互。小书签在网站上下文中执行,因此它可以访问 DOM。您可以按照自己的意愿与网站进行交互。当您准备好保存时,打开 Iframe。 iframe 将是一种只有一个保存按钮的确认屏幕。

诀窍是延迟 iframe 的创建。仅当用户准备好保存时才创建 iframe。

You can't make cross-site requests without eliminating the forgery part. But for your use case, I don't think you need cross-site requests.

Lets assume your service allows users to bookmark any pages he wishes. The job of the bookmarklet would be to save {url, title} into the database. At the same time, you want to prevent a malicious website automatically saving urls for a user who is logged in.

Here's what I would do to solve this -

  1. Create a page on your domain that has a standard html form with regular CSRF protection. This page takes in the parameters {url, pagetitle}, but will only save this tuple when the user explicitly clicks the "save" button.
  2. The bookmarklet's job is to load the iframe
  3. Once the iframe loads, its a normal same-origin request

This is more or less what Google reader does as part of its bookmarklet. Here is the code for its bookmarklet - notice it doesn't have any tokens


javascript:
var b=document.body;
var GR________bookmarklet_domain='http://www.google.com';
if(b&&!document.xmlVersion) {
  void(z=document.createElement('script'));
  void(z.src='http://www.google.com/reader/ui/link-bookmarklet.js');
  void(b.appendChild(z));
 }
 else{}

EDIT :
You can still support interactions with the iframe approach. The bookmarklet executes in context of the website, so it has access to the DOM. You can interact however you want with the website. When you are ready to save, open up the Iframe. The iframe will be a sort-of confirmation screen with just one save button.

The trick is to delay creation of the iframe. You only create the iframe when the user is ready to save.

傾城如夢未必闌珊 2024-10-26 16:01:18

如果小书签存储在网络浏览器中,那么包含在数据库中散列的密钥是一个好主意。这将防止 CSRF,尽管它并不理想,因为从某种意义上来说,这是一个不会超时的会话 ID。应该清楚的是,此令牌仅用于此小书签操作。尽管有此限制,您不太可能会遇到攻击。添加 HTTPS 将使这一点变得更强大,因为更难泄露此令牌。

如果小书签源自第 3 方网站,则您无能为力。这就是CSRF的定义。

If the bookmarklet is being stored in a web browser then the idea of including a secret key which hashed in the database is a good idea. This will prevent CSRF, although it is not ideal because in a sense this is a session id that doesn't time out. It should be clear that this token is only being used for this bookmarklet action. Despite this limitation it is unlikely that you will experience an attack. Adding HTTPS will make this stronger because it will be harder to spill this token.

If the bookmarklet is originating from a 3rd party site, then there is nothing you can do. This is the definition of CSRF.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文