草庐IT

c# - 在客户端和服务器之间保护用户名/密码的最佳实践

coder 2024-06-24 原文

有一个应用程序(C# WPF)需要“回拨”并从家庭服务器获取更新的内容。理论上可能有成千上万的客户端需要通过公共(public)互联网进行通信。

每个用户将首先使用用户名和密码进行注册。然后,当应用程序运行时,它会不时地回电,以获取有关新版本、新闻、评论、用户消息和其他应用程序特定内容的信息。这不会是“每个人”的应用程序,但如前所述,仍然可能有相当多的用户 - 因此安全性是重中之重。我希望它非常非常难以闯入,但如果不可能是一种选择,我也会这样做。 :)

只需要支持几个基本操作;

  • 新用户初始注册
  • 验证用户名和密码
  • A“自 [TIMESTAMP] 以来有什么新变化?”操作
  • 客户端发布评论、消息或其他允许的用户生成内容

  • 服务器端将在带有 IIS7 的 Win2008 服务器上。在我为项目所用的时间里,我几乎不具备使用 WCF 实现这一点所需的知识,因此我将使用 XML 文件来回执行一些 ASP.NET MVC 2 魔术。如果你只有一把锤子..

    我正在寻找的是关于如何尽可能安全地做到这一点而不使其无法使用的建议。客户端的配置将保存在 XML 文件中。在服务器端,大多数东西都将存在于 SQL 服务器中。

    我意识到这在某种程度上是一个见仁见智的问题,但我也相信应该有可能达到某种最佳实践,我可以在晚上 sleep 而不用担心客户端<->服务器通信和拥有帐户的用户被劫持等
  • 在客户端,我猜密码应该存储为哈希吗?或加密,有办法取回?
  • 我正在考虑客户端和服务器之间的 HTTPS 以获得一个很好的默认安全层。馊主意?不?
  • 真的有必要用这个模型“登录”吗?每个请求都应该发送用户名/密码组合吗?
  • 如果我使用 https,那么此时是否足够安全?或者我仍然应该加密一些身份验证的东西?
  • 服务器是否提供某种加密“ token ”,可以用作盐(我对这里的术语不太熟悉)来进一步加密用户名/密码?
  • 基本上,我怎样才能保护这个系统到客户端或服务器机器之外没有人可以窃取帐户信息的程度?我当然意识到,如果坏人获得了正确的配置文件,那么该帐户就会被盗用。这个系统当然不会允许使用这种通信进行任何关键操作,所有这些都将发生在服务器上;尽管如此,我认为帐户黑客是一件非常非常糟糕的事情,我应该采取一切可能的措施来避免。

  • 有什么好主意吗?

    谢谢!

    最佳答案

    您有两个不同的问题:验证注册用户和配置新用户帐户。
    验证用户
    这是简单的部分。您有多种选择:

  • HTTP 身份验证( basicdigest )。 Basic 是一个笑话,所以它真的只剩下 Digest 作为一个严肃的选择。
  • HTTP NTLM/Kerberos 身份验证(又名 Windows 集成身份验证)是万无一失的,前提是您的客户端已加入 NT 域(不太可能)。
  • SSL/TLS 相互认证
  • HTTP“表单”身份验证。微不足道。
  • 通过安全 channel 进行基本或表单例份验证 ( HTTPS )

  • 因此,剩下的真正选项是加密 channel 上的摘要、SSL 相互或基本/表单。
    HTTP 摘要 在客户端很容易实现,只需将用户名/密码添加到 CredentialCache WebRequest 一起使用你就完成了。在调用之间重用 CredentialCache 实例以从预身份验证中受益。不幸的是,服务器端的情况并不乐观:只有在与 AD 集成时才能正确支持摘要式身份验证,请参阅 Configure Digest Authentication .
    SSL/TLS 相互认证 客户端和服务器都支持,但同样,服务器端只有在与 AD 集成时才真正支持它,而不是真正的选项(参见 Configure Client Certificate Mapping Authentication )。
    这就是为什么我认为对于不打算在企业环境中通过 VPN 使用的应用程序的唯一现实选择是通过安全 channel (HTTPS) 使用基本或表单例份验证。对于 Basic,您必须提供 din 明文密码,对于 Forms(在其常见的、未修改的化身中)也是如此,因此客户端必须有权访问明文密码,服务器也是如此。一种方法散列不起作用,您需要适当的加密安全存储。
    现在是真的,因为您可以“增强”表单例份验证方案来做相当复杂的事情,基本上是在 HTTP 表单交换中设计一个 Digest 等价物,但我相信这超出了本讨论的范围。如果你沿着这条路冒险,你应该真正知道你在做什么,或者使用一个完善的解决方案(我不知道任何)。
    存储密码:对于 Basic/Digest/Forms,客户端不存储密码,因为密码实际上是由用户提供的。最多可以保存密码以避免重新输入,这应该像存储在客户端的任何用户特定 secret 一样完成,通过 ProtectedData 用 DPAPI 加密。类(class)。在服务器端,如果使用用户表,则密码应存储为单向哈希。对于 Basic 和 Form,任何散列方案都可以工作(最好是加盐的)。但是对于 Digest,散列必须是来自摘要方案的 HA1 散列:md5(username:realm:password)以便服务器可以完成身份验证握手。尽管这样做需要对 ASP 附带的开箱即用的成员资格提供程序进行一些相当侵入性的重写,但它仍然是我推荐的方式。
    配置用户
    这有点棘手,因为它涉及建立初始信任。如果您查看上面提到的所有方案,您会发现除了基于 HTTPS 的 Basic/Forms 之外,没有其他方案可以在带内执行此操作:任何其他解决方案都需要对通过带外方式设置的用户帐户进行初始部署(其中带外是指使用的方案)。相互 SSL 需要提供证书,NTLM/Kerberos 需要提供 AD 用户,Digest 需要提供用户密码。对于 Basic/Forms 和 Digest,有一个方便的“带外”解决方案:一个安全的 HTTPS channel ,用于提交帐户创建表单。对于 SSL/TLS 证书和 AD,事情更加复杂。
    OpenID/OAuth
    一种完全不同的方法是委托(delegate)身份验证。将 OpenID 与 Google 或 Yahoo 等提供商一起使用,将 OAuth 与 Facebook 或 Twitter 等提供商一起使用。这对于 Web 应用程序非常有效(StackOverflow 本身使用这样的方案,您可能已经注意到,参见 OpenID, One Year Later)。有一些库和集成提供程序可以让这一切变得像 3 次点击和一行代码一样简单,例如 JanRain .
    OpenID 和 OpenAuth 的唯一问题是它是一种交互式方案。它仅在用户积极参与登录/身份验证过程时才有效,从而消除所有自动化解决方案。如果您的应用程序正在执行任何类型的后台操作(例如作为服务运行),或者如果在没有用户参与的情况下使用应用程序 ID 进行“回拨”,则 OpenID/OAuth 不起作用。

    关于c# - 在客户端和服务器之间保护用户名/密码的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3451704/

    有关c# - 在客户端和服务器之间保护用户名/密码的最佳实践的更多相关文章

    1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    3. ruby-on-rails - Rails 应用程序之间的通信 - 2

      我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

    4. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

      最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

    5. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

      在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

    6. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

      在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

    7. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

      我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

    8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

      如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

    9. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

      您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

    10. C# 到 Ruby sha1 base64 编码 - 2

      我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

    随机推荐