C# 应用程序应向 php 网站发送一些数据,但应尊重身份验证策略
我遇到一种情况,我的 C# 应用程序需要与我的 Php 网站进行通信(是的,我有这两个网站的源代码,我可以毫无问题地进行编辑)。
我必须将一些数据从我的 C# 应用程序发送到 PHP 网站以更新数据库中的一些数据。
最大的问题是,我应该发送数据的这个网页受到身份验证机制的保护。
我在编辑此机制时没有任何问题,但是我需要一种安全的方式来发送(最终)用户名/密码和所需的数据。有什么安全的方法可以做到这一点?我认为以纯文本形式发送用户名和密码不是一个好主意,所以我正在寻找建议。
I have a situation where my C# Application need to communicate with my Php website (yes I have sources for both of them and I can edit without any problem).
I have to send some data from my C# app to PHP website to update some data in the database.
The biggest problem, is that this webpage where I should send data is protected with an authentication mechanism.
I don't have any problem in editing this mechanism, however I need a secure way to send (eventually) username/password and the data required. What's a secure way to do this? I don't think sending username and password as plain text is a good idea, so I was looking for suggestion.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
SSL + 请求中的用户名(可选;但如果您最终将拥有多个必须区分的客户端,这可能是必要的) + 使用与该用户名对应且两端都知道的密码对请求进行签名。
请注意,“签名”并不意味着通过网络发送密码。这意味着对部分或完整请求进行哈希处理,然后将该值包含在明文请求中。然后接收者(PHP)会做同样的事情,然后比较哈希值。签名确保只有知道密码的客户端才能发出请求;无效请求应被拒绝。
使用 SSL 证书加密(如果您在 php 端有它)只会有助于隐藏数据,以免被好奇的人发现。签名是验证客户端的方式。
创建一个匿名 php 处理程序(在您的身份验证规则中例外),这应该可以工作。
编辑:示例
假设您希望 C# 应用程序将以下数据传递到 PHP 应用程序:
假设您决定通过用户名
"uid"
和密码" 识别此客户端密码”。
签名数据涉及对其进行散列。散列意味着以不可能解密的方式对其进行加密(嗯,有点;我简化了;查一下)。有多种哈希算法,您必须找到一个适用于 C# 和 PHP 的库来执行此操作。最流行的(我猜)是“sha1”和“md5”。我什至不知道核心区别,我也不关心。我所知道的是,不同的值会被“翻译”为相当独特的哈希值。例如,尽管偏离主题,但在用户验证期间,通常将密码的哈希值存储在数据库中并比较哈希值,而不是比较明文密码。
在 .NET 中,您可以通过 System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile 方法对字符串值进行 sha1/md5 哈希处理。我对 PHP 知之甚少,但我相信您会找到一个功能完全相同的库。
因此,鉴于上述示例数据和上述凭据,您可以执行以下操作:
1 - 找到用户名的位置(以便您知道谁在发送请求;同样,如果您预计有多个客户端;否则,在您的情况下,您可以跳过此部分)。例如:
除此之外,您还可以执行各种操作:定义自己的格式(xml、json、分隔、二进制),或者如果数据很短并且您使用 HTTP GET,则对其进行编码并让数据和用户名成为两个不同的查询对,或将它们作为 post 参数进行 HTTP-POST。
2 - 上述数据仍然是明文数据。现在,签字。这可以通过多种方式完成,但我会使其变得简单:将明文密码添加到此数据中(无论在哪里,只要双方都知道该位置即可);例如,
请注意,我什至不关心我刚刚破坏了 xml 格式。您可以将其作为属性/元素放置在任何地方。这仍然是明文。
3 - 散列它。同样,使用哪种哈希算法并不重要,只要双方都知道即可。对于这个例子,我将使用许多在线哈希生成器之一:
http://www.joeswebtools.com/security/sha1-hash-generator/
当我将 #2 中的完整文本(包括密码)粘贴到该网站上时,我会得到这个(继续,您也可以尝试):
因此,给出完全相同的文本输入(区分大小写,敏感编码)散列总是会产生精确的相同的结果。 SHA1/MD5 是固定长度算法(我相信是 36 和 40 个字符;我现在懒得验证这一点)。
4 - 现在,将此哈希值添加到来自#1的原始请求数据中(任何位置,只要双方都知道);例如:
or
重要的是PHP需要知道在哪里可以找到哈希值以及如何将其解析出来。
5 - 将 #4 中的文本从 C# 发送到 PHP。到目前为止,我们所做的只是通过签名来确定发件人就是您所认为的人。它不是加密的:有多种方法可以拦截此请求并读取它(但是,没有人可以破译密码)。如果您也想加密它,这取决于您(您关心是否有人可以阅读此内容?)。加密数据的方法也有很多,但在 PHP 端使用 SSL 证书(然后通过 HTTPS 发送请求)可能是最简单、最便宜、最不容易出错/风险最小的方法,而且 - 我敢说 -最好的。如果您选择不加密,C# 将按照上面 #4 中的方式发送数据。
6 - PHP 接收数据。如果您使用 SSL,我很确定您无需执行任何操作即可解密(这将由 PHP 为您完成) - 因此,无论哪种情况,您的 PHP 脚本都将以明文形式接收数据。
7 - PHP 知道这种格式。如果由于任何原因解析此请求失败,请忽略该请求。我这么说是假设两端运行的代码没有与创建请求和读取请求相关的错误。
8 - PHP 从请求数据中删除签名(同时将其保留在内存中),结果是:
9 - PHP 从请求中读取用户名(“uid”)。然后它查找与其关联的密码(“pwd”)。然后,它执行与 C# 客户端在步骤 #2 和 #3 中执行的完全相同的操作,为自己生成以下内容:
10 - 签名形式 #9 必须与请求中提供的签名相同(来自 #8) ) - 区分大小写!如果不是,则有人试图假装自己是 uid 客户端。
11 - 现在 PHP 确定客户端是其友好的 C# 应用程序(我们称之为“信任”),它可以处理该请求。
可能有更优雅、更简单的方法。另外,在步骤 #2 中我告诉您添加密码,您可以添加密码的哈希值(假设您的 PHP 甚至没有明文密码,但它具有相同的哈希值)。
不,这个方法无法伪造。在不知道密码的情况下,我不可能向您发送一些恶意形成的请求,冒充您的 C# 客户端。然而,重播是可能的。重放的意思是:拦截请求,读取请求,然后按原样重新发送。这样做主要是为了在双方都不知情的情况下窃取信息。也有一些方法可以防止重播,但这超出了范围,而且您没有为军队做任何事情,不是吗?
现在,我想要所有这些信息和我的时间都得 A :)
SSL + username in request (optional; but if you will eventually have multiple clients that you have to differentiate, it's probably necessary) + SIGN the request with the password that corresponds to that username and is known on both ends.
Note that "signing" does not mean sending the password over the network. It means hashing a part or the complete request, then including that value in clear-text request. The recipient (PHP) would then do the same, then compare hashes. Signing ensures that only the client that knows the password can make the request; invalid requests should be rejected.
Encrypting with SSL certificate (if you have it on php side) helps only to hide the data from curious eyes. Signing is what verifies the client.
Make an anon php handler (make an exception in your auth rules), and this should work.
EDIT: EXAMPLE
Let's say that you want your C# app to pass the following data to your PHP app:
Let's say that you decided for this client to be recognized by username
"uid"
and password"pwd"
.Signing data relates to hashing it. Hashing means encrypting it in such a way that it cannot possibly be decrypted (well, kind of; I simplified that; look it up). There are several hashing algorithms, and you'll have to find a library to do it, for both C# and PHP. The most popular (I guess) are "sha1" and "md5". I don't even know the core difference, neither do I care. All I know is that different values get to be "translated" to fairly unique hash values. For example - although, off-topic, it's common to store hash values of passwords in the database, and compare hashes, rather then be comparing clear-text password, during user validation.
In .NET, you can sha1/md5 hash string values by method
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile
. I know very little about PHP, but I'm sure you'll find a library that does exactly the same.So, given the above example data, and above credentials, you could do the following:
1 - Find the place for the username (so, that you know who's sending the request; again, if you anticipate having multiple clients; otherwise, in your case, you can skip this). For example:
Instead of this, you can do various things: define your own format (xml, json, delimited, binary), or if the data is short and you're using HTTP GET, then encode it and have data and username be two different query pairs, or HTTP-POST them as post arguments.
2 - The above data is still clear-text. Now, signing. This can be done in multiple ways, but I'll make it simple: add the clear-text password to this data (doesn't matter where, as long that location is known to both parties); e.g.
Notice how I don't even care that I just broke the xml-format. You could have placed it as an attribute/element - anywhere. That's still clear-text.
3 - Hash it. Again, it doesn't matter which hash algorithm you use, as long it's known to both parties. For this example, I'll use one of many online hash generators that are out there:
http://www.joeswebtools.com/security/sha1-hash-generator/
When I paste the complete text (including the password) from #2 over on that site, I'll get this (go ahead and you also try):
So, given the exact same text input (case sensitive, encoding sensitive) hashing will always produce the exact same result. SHA1/MD5 are fixed-length algorithms (36 and 40 chars, I believe; I'm lazy to verify that right now).
4 - Now, add this hashed value to the original request data from #1 (any spot, as long as it's known to both parties); for example:
or
The important thing is that PHP needs to know where to find the hash value and how to parse it out.
5 - Send the text from #4 from C# to PHP. What we did so far was only signing to be certain that the sender is who you think it is. It is not encrypting: there are ways to intercept this request and read it (however, nobody can decipher the password). It is up to you if you also want to encrypt it (do you care if somebody can read this?). There are bunch of ways to encrypt data as well, but using SSL certificate on PHP side (and then sending the request over HTTPS) is probably your simplest, cheapest, the least error-prone/risky method, and - I dare say - the best. If you choose not to encrypt, C# sends the data as it is in #4 above.
6 - PHP receives the data. If you used SSL, I'm pretty sure you won't have to do anything to decrypt it (it will be done by PHP for you) - so, in either case, your PHP script will receive the data in clear-text.
7 - PHP knows about this format. If parsing this request fails for any reason, ignore the request. I said this assuming that the code running on both ends has no bugs related to creating the request and reading it.
8 - PHP removes the the signature from the request data (while keeping it in memory), resulting in this:
9 - PHP reads the username from the request ("uid"). It then looks up the password associated with it ("pwd"). It then does the exact same things that the C# client did in steps #2 and #3, producing the following for itself:
10 - The signature form #9 has GOT TO be the same as the signature provided in the request (from #8) - case-sensitive! If it's not, somebody is trying to pretend they are the uid client.
11 - Now that PHP is certain that the client is its friendly C# app (let's call this "the trust"), it can process the request.
There may be more elegant ways, possibly simpler. Also, where in step #2 I told you add the password, you could instead add the HASH of the password (assuming your PHP doesn't even have the clear-text password, but it has that same HASH instead).
No, this method cannot be faked. It is impossible for me to - without knowing the password - to send you some maliciously-formed request pretending to be your C# client. However, replaying IS possible. Replaying means: intercepting the request, reading it, and resending it as it. This is mostly done to steal information without neither of the 2 parties knowing. There are ways to prevent replaying also, but it's out of scope, and you're not doing anything for the military, are you?
Now, I want an A for all this info and my time :)