简体   繁体   English

如何使用 SSL/TLS 和/或消息级安全性保护 RESTful php web 服务

[英]How to secure a RESTful php web service with SSL/TLS and/or Message level security

I have a RESTful web service written in php that uses JSON for communication.我有一个用 php 编写的 RESTful web 服务,它使用 JSON 进行通信。 Some of the data transmitted is really sensitive (passwords) and I am looking for a way to achieve a reasonable security level for the service.传输的一些数据非常敏感(密码),我正在寻找一种方法来为服务实现合理的安全级别。 The client is a silverlight 4 application.客户端是 silverlight 4 应用程序。

I have been searching for clear information on how to implement SSL/TLS(I assume that client certificate authentication falls in that category?) and Message level security, but I cannot find good examples regarding the actual implementation of these security measures in a php+json web service.我一直在寻找有关如何实施 SSL/TLS(我假设客户端证书身份验证属于该类别?)和消息级别安全性的明确信息,但我找不到关于在 php+ 中实际实施这些安全措施的好例子json web 服务。 I would be very grateful for any information and practical examples.我将非常感谢任何信息和实际示例。 I am aware of the principles, I am just not very experienced with php.我知道这些原则,我只是对 php 不是很有经验。 Currently the only security measure that I have in place is a very basic authentication token system, which upon successful login creates a server side session and supplies the user with an authentication token for any further communication(until the session expires or the user connects from a different IP).目前,我采用的唯一安全措施是一个非常基本的身份验证令牌系统,成功登录后会创建一个服务器端 session 并为用户提供身份验证令牌以进行任何进一步的通信(直到 session 过期或用户从不同的IP)。 I really want to at least secure the sensitive traffic such as passwords.我真的很想至少保护密码等敏感流量。

Finally, what are the security issues that I have to look out for after implementing TLS and maybe message layer security, as in vulnerabilities and exploits?最后,在实施 TLS 和消息层安全之后,我必须注意哪些安全问题,例如漏洞和利用?

Thank you in advance.先感谢您。

Assuming you have HTTPS properly configured using SSL/TLS your main concern is how to implement authentication for your RESTful service.假设您使用 SSL/TLS 正确配置了 HTTPS,您主要关心的是如何为您的 RESTful 服务实施身份验证。 Since HTTPS will use SSL/TLS to encrypt the communication between client and server encryption is not something you should worry about.由于 HTTPS 将使用 SSL/TLS 来加密客户端和服务器之间的通信,因此您不必担心。 If you need to understand how to properly configure SSL/TLS read Understanding SSL/TLS如果您需要了解如何正确配置 SSL/TLS,请阅读了解 SSL/TLS

Best practices for securing RESTful service is already discussed in RESTful Authentication and Best Practices for securing a REST API / web service . RESTful 身份验证保护 REST API / web 服务的最佳实践中已经讨论了保护 RESTful 服务的最佳实践。

To summarize it discusses 3 options总结它讨论了3个选项

  • HTTP basic auth over HTTPS HTTP 基本认证 HTTPS
  • Cookies and session management Cookies 和 session 管理
  • Query Authentication with additional signature parameters.使用附加签名参数查询身份验证。

Another option would be to explore OAuth2 for authentication.另一种选择是探索 OAuth2 进行身份验证。 If so you can get a good understanding about Oauth2 in Beginner's Guide to OAuth Part III: Security Architecture如果是这样,您可以在OAuth 初学者指南第三部分:安全架构中对 Oauth2 有一个很好的理解

You should already be using SSL to get the authentication established.您应该已经在使用 SSL 来建立身份验证。

Then you can use same token you got after authentication as your secret hash to encrypt/decrypt data back and forth for that connection until it becomes invalid.然后,您可以使用身份验证后获得的相同令牌作为您的秘密 hash 来为该连接来回加密/解密数据,直到它变得无效。

If systems are properly locked down (internal) you can skip SSL for encrypted data transfer if you need more speed (as long as original token is generated over SSL, and system is aware what IP the token is assigned to/etc).如果系统被正确锁定(内部),您可以跳过 SSL 进行加密数据传输,如果您需要更快的速度(只要原始令牌是通过 SSL 生成的,并且系统知道 ZA12A3079E14CED46E69BA52B8A 等)。

As far as I understood, you have an existing code in place.据我了解,您有一个现有的代码。 To make it easier, I will show you a simple example and how things work with the code below.为了方便起见,我将向您展示一个简单的示例以及如何使用下面的代码。 Feel free to use only the parts you need (which should be pretty straight forward).随意只使用你需要的部分(这应该很简单)。

The way you have currently created your app works just fine with the server side sessions.您当前创建应用程序的方式适用于服务器端会话。

Under the code below, I will include some more explanation and links to resources, which will help you better understand the code, test and debug your app.在下面的代码下,我将包含更多解释和资源链接,这将帮助您更好地理解代码、测试和调试您的应用程序。

$Web_Service_URL = 'https://website.tld/webservice.lang?wsdl';
$debug = false;
$proto = 'https'; // e.g. str 'https'
$agent = 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0';
$download = false; // just to make a call and fetch nothing set to false
//$download = '/location/my_file.html';  to fetch content and save to file set the file location

// Init the cURL session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $Web_Service_URL);

/** 
 * 
 * Start Fix SSLv3/TLS connectivity problems
 * 
 * CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER prevent MITM attacks
 * WARNING: Disabling this would prevent curl from detecting Man-in-the-middle (MITM) attack
 * 
 */

/**
 * @param CURLOPT_SSL_VERIFYPEER
 * 
 * FALSE to stop CURL from verifying the peer's certificate.
 * Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option.
 * CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2).
 * Setting CURLOPT_SSL_VERIFYHOST to 2 (This is the default value) will garantee that the certificate being presented to you have a 'common name' matching the URN you are using to access the remote resource.
 * This is a healthy check but it doesn't guarantee your program is not being decieved.
 * 
 */
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

/**
 * @param CURLOPT_VERBOSE
 * Set the on/off parameter to 1 to make the library display a lot of verbose information about its operations on this handle. 
 * Very useful for libcurl and/or protocol debugging and understanding. The verbose information will be sent to stderr, 
 * or the stream set with CURLOPT_STDERR.
 * You hardly ever want this set in production use, you will almost always want this when you debug/report problems.
 */ 
curl_setopt($ch, CURLOPT_VERBOSE, $debug);

/**
 *  
 * @param CURLOPT_SSL_VERIFYHOST
 * 
 * Check the existence of a common name in the SSL peer certificate.
 * Check the existence of a common name and also verify that it matches the hostname provided.
 * 
 * @value 1 to check the existence of a common name in the SSL peer certificate. 
 * @value 2 to check the existence of a common name and also verify that it matches the hostname provided.
 * In production environments the value of this option should be kept at 2 (default value).
 * Support for value 1 removed in cURL 7.28.1 
 */
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

/**
 * 
 * Force use of TLS
 * 
 */
if($proto == 'https')
{
    /**
     *
     * Let's explain the magic of comparing your TLS certificate to the verified CA Authorities and how does that affect MITM attacks
     *  
     * Man in the middle (MITM)
     * Your program could be misleaded into talking to another server instead. This can be achieved through several mechanisms, like dns or arp poisoning.
     * The intruder can also self-sign a certificate with the same 'comon name' your program is expecting. 
     * The communication would still be encrypted but you would be giving away your secrets to an impostor.
     * This kind of attack is called 'man-in-the-middle'
     * Defeating the 'man-in-the-middle'
     * We need to to verify the certificate being presented to us is good for real. We do this by comparing it against a certificate we reasonable* trust.
     * If the remote resource is protected by a certificate issued by one of the main CA's like Verisign, GeoTrust et al, you can safely compare against Mozilla's CA certificate bundle, 
     * which you can get from http://curl.haxx.se/docs/caextract.html
     *
     */
    //TODO: If TLSv1_1 found insecure and/or unreliable change to TLSv1_1 or TLS1_2
    curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); // CURL_SSLVERSION_TLSv1_1; CURL_SSLVERSION_TLSv1_2
    curl_setopt($ch, CURLOPT_HEADER, 0); // Don’t return the header, just the html

    if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
        $crt = substr(__FILE__, 0, strrpos( __FILE__, '\\'))."\crt\cacert.crt"; // WIN
    }
    else {
        $crt = str_replace('\\', '/', substr(__FILE__, 0, strrpos( __FILE__, '/')))."/crt/cacert.crt"; // *NIX
    }

    // The cert path is relative to this file
    curl_setopt($ch, CURLOPT_CAINFO, $crt); // Set the location of the CA-bundle

    /** 
     * Fix Error: 35 - Unknown SSL protocol error in connections
     * 
     * Improve maximum forward secrecy
     */
    // Please keep in mind that this list has been checked against the SSL Labs' WEAK ciphers list in 2014.
    $arrayCiphers = array(
    'DHE-RSA-AES256-SHA',
    'DHE-DSS-AES256-SHA',
    'AES256-SHA',
    'ADH-AES256-SHA',
    'KRB5-DES-CBC3-SHA',
    'EDH-RSA-DES-CBC3-SHA',
    'EDH-DSS-DES-CBC3-SHA',
    'DHE-RSA-AES128-SHA',
    'DHE-DSS-AES128-SHA',
    'ADH-AES128-SHA',
    'AES128-SHA',
    'KRB5-DES-CBC-SHA',
    'EDH-RSA-DES-CBC-SHA',
    'EDH-DSS-DES-CBC-SHA:DES-CBC-SHA',
    'EXP-KRB5-DES-CBC-SHA',
    'EXP-EDH-RSA-DES-CBC-SHA',
    'EXP-EDH-DSS-DES-CBC-SHA',
    'EXP-DES-CBC-SHA'
    );

    curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, implode(':', $arrayCiphers));
}

curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

if($debug == true)
{curl_setopt($ch, CURLOPT_HEADER, 1);} // Get HTTP Headers Code
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

// ini_set('user_agent', 'NameOfAgent (http://www.example.net)');
curl_setopt($ch, CURLOPT_USERAGENT, $agent);

/**
 * DEBUG cURL Call
 * Don't forget to uncomment the CURLOPT_HEADER'
 */
    // Get HTTP Headers Code
    // Show Http Header
if($debug == true)
{
    echo "<pre>";
    echo curl_getinfo($ch, CURLINFO_HTTP_CODE);
}

// TODO:Check if any cURL connection error occurred
// see http://php.net/manual/en/function.curl-errno.php
/** 
if(curl_errno($ch))
{
    echo 'Curl error: ' . curl_error($ch);
}
*/

// Send the request and check the response

if (($result = curl_exec($ch)) === FALSE) {
    die('cURL error: '.curl_error($ch)."<br />");
} else {
    //echo "Success!<br />";
}

/** 
 * @function cURL_GetInfo
 * other debug info, if needed
 * 
 * The var_dump output:
 * array(26) { 
 *          ["url"]=> string(61) "https://www.example.com" 
 *          ["content_type"]=> string(24) "text/html; charset=UTF-8" 
 *          ["http_code"]=> int(200) 
 *          ["header_size"]=> int(2462) 
 *          ["request_size"]=> int(493) 
 *          ["filetime"]=> int(-1) 
 *          ["ssl_verify_result"]=> int(0) 
 *          ["redirect_count"]=> int(2) 
 *          ["total_time"]=> float(0.286363) 
 *          ["namelookup_time"]=> float(7.1E-5) 
 *          ["connect_time"]=> float(0.011754) 
 *          ["pretransfer_time"]=> float(0.082954) 
 *          ["size_upload"]=> float(0) 
 *          ["size_download"]=> float(119772) 
 *          ["speed_download"]=> float(418252) 
 *          ["speed_upload"]=> float(0) 
 *          ["download_content_length"]=> float(262) 
 *          ["upload_content_length"]=> float(0) 
 *          ["starttransfer_time"]=> float(0.156201) 
 *          ["redirect_time"]=> float(0.076769) 
 *          ["certinfo"]=> array(0) { } 
 *          ["primary_ip"]=> string(14) "xxx.xxx.xxx.xxx." 
 *          ["primary_port"]=> int(443) 
 *          ["local_ip"]=> string(12) "192.168.0.15" 
 *          ["local_port"]=> int(54606) 
 *          ["redirect_url"]=> string(0) ""
 * }
 */ 
$info = curl_getinfo($ch);
$arrCodes = array(
    "client_error" => array("400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417"),
    "server_error" => array("500", "502", "503", "504", "505")
);

// Return the error code, if any and exit
if(in_multi_array($info['http_code'], $arrCodes))
{
    file_put_contents("logs/dberror.log", "Date: " . date('M j Y - G:i:s') . " --- Error: " . $info['http_code'].' URL: '.$info['url'].PHP_EOL, FILE_APPEND);
    return $info['http_code']; exit;
}

curl_close($ch);

// If download is defined download to the specified file
if($download!= false)
{
    $f = fopen($download, "w");
    fwrite($f, $result);
    fclose($f);
    echo 'Web content downloaded to a file';
}
echo $result;

As you can see in the code, you can define multiple secure ciphers, but only one SSL version parameter.正如您在代码中看到的,您可以定义多个安全密码,但只能定义一个 SSL 版本参数。 I wouldn't use anything earlier than TLS 1.1.我不会使用早于 TLS 1.1 的任何东西。 Any earlier SSL version is vulnerable to attack.任何早期的 SSL 版本都容易受到攻击。 Start with the most secure TLS 1.2 and test, if your app is working (usually, you shouldn't have any problems. If you experience any connectivity issues try TLS 1.1. TLS version 1.1 is also vulnerable, the only secure (for now, until they discover some vulnerability) is TLS 1.2.从最安全的 TLS 1.2 开始并测试您的应用程序是否正常运行(通常,您应该没有任何问题。如果您遇到任何连接问题,请尝试 TLS 1.1。TLS 版本 1.1 也容易受到攻击,唯一安全的(目前,直到他们发现一些漏洞)是 TLS 1.2。

If security is top priority, go with the highest available TLS version (TLS1.2).如果安全性是重中之重,则 go 具有最高可用 TLS 版本 (TLS1.2)。 Client compatibility is not your problem when there is service provider security liability.当存在服务提供商安全责任时,客户端兼容性不是您的问题。

Some others cURL parameters to look at:其他一些cURL参数看看:

The ciphers were checked against the strong Qualys SSL Labs list (2014) and weak ciphers were removed.这些密码已根据 Qualys SSL 实验室强列表 (2014) 进行检查,并删除了弱密码。 Feel free to add/remove any ciphers.随意添加/删除任何密码。

  1. Before you make a decision take a look at the Qualys SSL Labs' projects about security.在您做出决定之前,请查看 Qualys SSL 实验室关于安全性的项目
  2. Take a look at this SSL Labs' article about perfect forward secrecy and best practices.看看这篇 SSL Labs 关于完美前向保密和最佳实践的文章
  3. Test your client (web browser) for any vulnerabilities with SSL Labs' web tool .使用SSL Labs 的 web 工具测试您的客户端(Web 浏览器)是否存在任何漏洞。 This will give you an idea what to look at and what to improve and secure on your server and app.这将使您了解在您的服务器和应用程序上要查看的内容以及要改进和保护的内容。
  4. Test your website/web service with Qualys' SSL Labs SSL tool .使用 Qualys 的 SSL Labs SSL 工具测试您的网站/网络服务。

Vulnerabilities and attacks: Longjam, FREAK, POODLE, you name it?漏洞和攻击:Longjam、FREAK、POODLE,你的名字? Who knows what other attacks or vulnerabilities are undiscovered.谁知道还有哪些其他攻击或漏洞未被发现。 Yes!是的! They all affect your choice of SSL/TLS connection.它们都会影响您对 SSL/TLS 连接的选择。

Possible CURLOPT_SSLVERSION options can be found at the official cURL page: http://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.html可以在官方 cURL 页面上找到可能的 CURLOPT_SSLVERSION 选项: http://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.ZFC35FDC70D5FC69D23EZCA73

Here's also a nice OWASP guide for creating a secure layer around your app.这也是一个很好的OWASP 指南,用于在您的应用程序周围创建安全层

OWASP and Qualys SSL Labs are great resources to start with. OWASP 和 Qualys SSL 实验室是很好的入门资源。 I would even do some research on cURL and OpenSSL to get familiar with weaknesses, possible security options and best practices.我什至会对 cURL 和 OpenSSL 进行一些研究,以熟悉弱点、可能的安全选项和最佳实践。

There are security points, which I am not mentioning and are missing, but we can't cover everything.有一些安全点,我没有提到并且缺少,但我们不能涵盖所有内容。

If you have any questions, I will be around to answer, if I can.如果您有任何问题,如果可以的话,我会在附近回答。

This might be too elementary for your situation since I don't know anything about Silverlight, but what about getting an SSL certificate for your Web API?这对于您的情况来说可能太简单了,因为我对 Silverlight 一无所知,但是为您的 ZC6E190B284633C48E39E55049DA3CCE83A167423187014ADB97423187014 获取 SSL 证书怎么样? As in making your API so it's accessed only via the https:// protocol instead of http://.就像制作 API 一样,它只能通过 https:// 协议而不是 http:// 访问。 That will encrypt anything transmitted between client and server.这将加密客户端和服务器之间传输的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM