6

我正在编写一个应用程序,其主要目的是保留用户购买列表。

我想确保即使我作为开发人员(或任何可以完全访问数据库的人)也无法弄清楚某个人花了多少钱或买了什么。

我最初想出了以下方案:

    --------------+------------+------------
    用户哈希 | 项目 | 价格
    --------------+------------+------------
    a45cd654fe810 | 脱衣舞俱乐部 | 400.00
    a45cd654fe810 | 法拉利 | 1510800.00
    54da2241211c2 | 啤酒 | 5.00
    54da2241211c2 | 苹果手机 | 399.00
  • 用户使用用户名和密码登录。
  • 从密码计算user_hash(可能与加盐等)。
  • 使用散列通过普通 SQL 查询访问用户数据。

如果有足够多的用户,只知道一个特定用户的名字几乎不可能知道他花了多少钱。

这是明智的做法,还是我完全愚蠢?

4

7 回答 7

4

恐怕如果您的应用程序可以将一个人链接到其数据,那么任何开发人员/管理员都可以。

您唯一能做的就是让链接变得更难,从而减慢开发人员/管理员的速度,但如果您更难将用户链接到数据,您的服务器也会变得更难。


基于@no idea 的想法:

您可以使用经典的用户/密码登录到您的应用程序(散列密码或其他),以及用于保护数据安全的特殊“通行证”。此“通行证”不会存储在您的数据库中。

当您的客户登录您的应用程序时,我必须提供用户/密码/密码。使用数据库检查用户/密码,并且通行证将用于加载/写入数据。

当您需要写入数据时,您可以对“用户名/密码”对进行哈希处理,并将其存储为将客户端链接到数据的密钥。

当您需要加载数据时,您可以对“用户名/密码”对进行哈希处理,然后加载与该哈希匹配的所有数据。

这样就不可能在您的数据和用户之间建立链接。

另一方面,(正如我在对@no 的评论中所说)提防碰撞。另外,如果您的用户写了一个糟糕的“通行证”,您将无法检查它。


更新:对于最后一部分,我有另一个想法,您可以在数据库中存储您的“通行证/密码”对的哈希值,这样您就可以检查您的“通行证”是否正常。

于 2010-09-17T17:26:35.463 回答
2
  1. 创建一个用户表:
    1. user_id:一个标识列(自动生成的 id)
    2. 用户名
    3. 密码:确保它是散列的!
  2. 创建一个产品表,如您的示例中所示:
    1. 用户哈希
    2. 物品
    3. 价格

user_hash 将基于永远不会改变的 user_id。用户名和密码可根据需要自由更改。当用户登录时,您比较用户名/密码以获取 user_id。您可以在会话期间将 user_hash 或哈希的加密/间接版本发送回客户端(可以是会话 ID,服务器将 user_hash 存储在会话中)。

现在您需要一种将 user_id 散列到 user_hash 并对其进行保护的方法。

  1. 如果您按照@no 的建议在客户端执行此操作,则客户端需要具有 user_id。巨大的安全漏洞(特别是如果它是一个网络应用程序),哈希很容易被篡改,算法可以免费提供给公众。
  2. 您可以将其作为数据库中的一个函数。坏主意,因为数据库具有链接记录的所有部分。
  3. 对于网站或客户端/服务器应用程序,您可以在服务器端代码中使用它。好多了,但是一位开发人员可以访问散列算法和数据。
  4. 让另一位开发人员编写散列算法(您无权访问)并将其作为 TCP/Web 服务插入另一台服务器(您也无权访问)。然后,您的服务器端代码将传递用户 ID 并返回一个哈希值。您不会拥有该算法,但您可以发送所有用户 ID 以获取他们的所有哈希值。对#3 没有太多好处,尽管该服务可以进行日志记录等以尽量减少风险。
  5. 如果它只是一个客户端-数据库应用程序,您只有选择 #1 和 2。我强烈建议添加另一个服务器端的 [business] 层,与数据库服务器分开。

编辑: 这与前面的一些观点重叠。拥有3台服务器:

  • 身份验证服务器:员工 A 有权访问。维护用户表。具有采用用户/密码组合的 Web 服务(具有加密通信)。哈希密码,在表中查找 user_id,生成 user_hash。这样您就不能简单地发送所有 user_id 并取回哈希值。您必须拥有未存储在任何地方且仅在身份验证过程中可用的密码。
  • 主数据库服务器:员工 B 有权访问。只存储 user_hash。没有用户名,没有密码。您可以使用 user_hash 链接数据,但实际的用户信息在其他地方。
  • 网站服务器:员工 B 可以访问。获取登录信息,传递到身份验证服务器,获取哈希,然后处理登录信息。在会话中保持哈希以写入/查询数据库。

所以员工 A 有 user_id、用户名、密码和算法。员工 B 有 user_hash 和数据。除非员工 B 修改网站以存储原始用户/密码,否则他无法链接到真实用户。

使用 SQL 分析,员工 A 将获得 user_id、用户名和密码哈希(因为 user_hash 稍后在代码中生成)。员工 B 将获得 user_hash 和数据。

于 2010-09-17T19:03:04.490 回答
2

请记住,即使没有在任何地方实际存储此人的身份信息,只要将足够多的信息都与同一个密钥相关联,就可以让您找出与某些信息相关联的人的身份。举个简单的例子,你可以打电话给脱衣舞俱乐部,询问哪个顾客开着法拉利。

出于这个原因,当您对医疗记录进行去标识化(用于研究等)时,您必须删除 89 岁以上的人的生日(因为这个年龄的人非常罕见,以至于特定的生日可能指向一个人)并删除任何指定包含少于 20,000 人的区域的地理编码。(见http://privacy.med.miami.edu/glossary/xd_deidentified_health_info.htm

AOL 在发布搜索数据时发现了一个艰难的方法,即仅通过知道哪些搜索与匿名人相关联就可以识别人们。(见http://www.fi.muni.cz/kd/events/cikhaj-2007-jan/slides/kumpost.pdf

于 2010-09-17T20:04:43.077 回答
1

确保数据无法与其所属的人相关联的唯一方法是首先不记录身份信息(使所有内容匿名)。但是,这样做很可能会使您的应用程序毫无意义。你可以让这件事变得更难做,但你不能让它变得不可能。

将用户数据和识别信息存储在单独的数据库中(也可能在单独的服务器上)并将两者与 ID 号链接可能是您能做的最接近的事情。这样,您就尽可能地隔离了两个数据集。您仍然必须保留该 ID 号作为它们之间的链接;否则,您将无法检索用户的数据。

此外,我不建议使用散列密码作为唯一标识符。当用户更改密码时,您必须检查并更新所有数据库,以用新的密码 ID 替换旧的散列密码 ID。使用不基于任何用户信息的唯一 ID 通常更容易(以帮助确保它保持静态)。

这最终成为一个社会问题,而不是技术问题。最好的解决方案将是社会解决方案。在强化您的系统以防止未经授权的访问(黑客等)之后,您可能会在与用户建立信任并实施有关数据安全的政策和程序系统方面获得更好的成绩。包括对滥用客户信息的员工的具体处罚。由于一次违反客户信任就足以毁掉您的声誉并赶走所有用户,因此具有“顶级”访问权限的人滥用这些数据的诱惑比您想象的要少(因为公司通常会倒闭超过任何收益)。

于 2010-09-17T17:54:14.053 回答
0

问题在于,如果某人已经拥有对数据库的完全访问权限,那么他们将记录链接到特定的人只是时间问题。在您的数据库(或应用程序本身)的某个地方,您必须在用户和项目之间建立关系。如果某人具有完全访问权限,那么他们将有权访问该机制。

绝对没有办法阻止这种情况。

现实情况是,通过完全访问,我们处于信任的位置。这意味着公司经理必须相信,即使您可以看到数据,您也不会对其采取任何行动。这就是道德等小事发挥作用的地方。

也就是说,现在很多公司将开发人员和生产人员分开。目的是使开发人员不再直接接触实时(即:真实)数据。这具有许多优势,安全性和数据可靠性处于最重要的位置。

唯一真正的缺点是一些开发人员认为他们无法在没有生产访问权限的情况下解决问题。然而,这根本不是真的。

然后,生产人员将是唯一可以访问实时服务器的人员。他们通常会接受更大程度的审查(犯罪历史和其他背景调查),这与您必须保护的数据类型相得益彰。

这一切的关键在于这是一个人事问题。而不是真正可以通过技术手段解决的。


更新

这里的其他人似乎错过了这个难题中一个非常重要和至关重要的部分。即,数据被输入系统是有原因的。这个原因几乎是普遍的,因此可以共享。在费用报告的情况下,输入该数据以便会计可以知道谁来偿还。

这意味着系统在某种程度上必须在没有数据输入人员(即:销售人员)登录的情况下匹配用户和项目。

而且因为这些数据必须绑定在一起,所有相关方都站在那里输入安全代码来“发布”数据,因此 DBA 绝对能够查看查询日志以确定谁是谁。而且很容易我可以添加,无论您要添加多少哈希标记。三重 DES 也不会拯救你。

归根结底,您所做的只是让开发更加困难,而安全收益绝对为零。这一点我怎么强调都不过分:向 dba 隐藏数据的唯一方法是 1. 该数据只能由输入它的人访问,或者 2. 它一开始就不存在。

关于选项 1,如果唯一可以访问它的人是输入它的人.. 那么,将它放在公司数据库中是没有意义的。

于 2010-09-17T17:32:55.580 回答
0

实际上,有一种方法可以做到你所说的......

您可以让用户将他的姓名和密码输入到一个运行纯客户端脚本的表单中,该脚本会根据名称和密码生成哈希。该哈希用作用户的唯一 ID,并发送到服务器。这样,服务器只通过哈希而不是名称知道用户。

但是,要使其正常工作,散列必须与普通密码散列不同,并且用户将需要再输入一次他们的姓名/密码,然后服务器才能“记忆”那个人所购买的东西。

服务器可以记住该人在会话期间购买了什么,然后“忘记”,因为数据库不包含用户帐户和敏感信息之间的链接。

编辑

对于那些说客户端散列存在安全风险的人的回应:如果你做对了,那就不是。应该假设散列算法是已知的或可知的。否则就等于“通过默默无闻获得安全”。散列不涉及任何私钥,动态散列可用于防止篡改。

例如,您采用这样的哈希生成器:

http://baagoe.com/en/RandomMusings/javascript/Mash.js

// From http://baagoe.com/en/RandomMusings/javascript/
// Johannes Baagoe <baagoe@baagoe.com>, 2010
function Mash() {
  var n = 0xefc8249d;

  var mash = function(data) {
    data = data.toString();
    for (var i = 0; i < data.length; i++) {
      n += data.charCodeAt(i);
      var h = 0.02519603282416938 * n;
      n = h >>> 0;
      h -= n;
      h *= n;
      n = h >>> 0;
      h -= n;
      n += h * 0x100000000; // 2^32
    }
    return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
  };

  mash.version = 'Mash 0.9';
  return mash;
}

看看n变化如何,每次你散列一个字符串时,你都会得到不同的东西。

  • 使用普通哈希算法对用户名+密码进行哈希处理。这将与数据库中“秘密”表的键相同,但不会匹配数据库中的其他任何内容。
  • 将散列传递附加到用户名并使用上述算法对其进行散列。
  • Base-16 编码var n并将其附加到带有分隔符的原始哈希中。

这将创建一个唯一的哈希(每次都会不同),系统可以针对数据库中的每一列进行检查。该系统可以设置为只允许一个特定的唯一哈希值一次(例如,一年一次),从而防止 MITM 攻击,并且用户的任何信息都不会通过网络传递。除非我遗漏了什么,否则没有什么不安全的。

于 2010-09-17T17:34:42.387 回答
0

看起来你在这方面是正确的,但你只是想多了(或者我根本不明白)

编写一个函数,根据输入构建一个新字符串(这将是他们的用户名或其他不能随时间改变的东西)

在构建用户哈希时使用返回的字符串作为盐(我再次使用用户 ID 或用户名作为哈希构建器的输入,因为它们不会像用户的密码或电子邮件一样更改)

将所有用户操作与用户哈希关联。

只有数据库访问权限的人无法确定用户哈希的含义。即使尝试通过尝试不同的种子来强制它,盐组合最终也将毫无用处,因为盐被确定为用户名的变体。

我想你已经用你最初的帖子回答了你自己的问题。

于 2010-09-17T20:18:39.180 回答