Как защитить веб-сервис RESTful php с помощью SSL / TLS и / или безопасности на уровне сообщений - PullRequest
9 голосов
/ 05 июля 2011

У меня есть веб-сервис RESTful, написанный на php, который использует JSON для связи.Некоторые из передаваемых данных действительно конфиденциальны (пароли), и я ищу способ достижения разумного уровня безопасности для службы.Клиент является приложением silverlight 4.

Я искал четкую информацию о том, как реализовать SSL / TLS (я предполагаю, что аутентификация сертификата клиента попадает в эту категорию?) И безопасности на уровне сообщений, но не могу найтихорошие примеры относительно фактической реализации этих мер безопасности в веб-сервисе php + json.Буду очень признателен за любую информацию и практические примеры.Я знаю о принципах, я просто не очень опытный с php.В настоящее время единственная мера безопасности, которую я имею в наличии, - это очень простая система токенов аутентификации, которая при успешном входе в систему создает сеанс на стороне сервера и предоставляет пользователю токен аутентификации для любого дальнейшего обмена данными (пока не истечет сеанс или пользователь не подключится изразные IP).Я действительно хочу, по крайней мере, защитить конфиденциальный трафик, такой как пароли.

Наконец, какие проблемы с безопасностью я должен рассмотреть после реализации TLS и, возможно, безопасности на уровне сообщений, как в случае уязвимостей и эксплойтов?

Заранее спасибо.

Ответы [ 4 ]

5 голосов
/ 24 августа 2012

Если вы правильно настроили HTTPS с использованием SSL / TLS, ваша главная задача - как внедрить аутентификацию для вашей службы RESTful.Поскольку HTTPS будет использовать SSL / TLS для шифрования связи между клиентом и сервером, шифрование - это не то, о чем вам следует беспокоиться.Если вам необходимо понять, как правильно настроить SSL / TLS, прочитайте Общие сведения о SSL / TLS

Рекомендации по обеспечению безопасности службы RESTful уже обсуждались в Аутентификация RESTful и Рекомендации по обеспечению безопасности API REST / веб-службы .

Для подведения итогов рассматриваются 3 варианта

  • Базовая аутентификация HTTP через HTTPS
  • Управление файлами cookie и сеансами
  • Аутентификация запросов с дополнительными параметрами подписи.

Другой вариант - использовать OAuth2 для аутентификации.Если это так, вы можете получить хорошее представление об Oauth2 в Руководство для начинающих по OAuth, часть III: Архитектура безопасности

2 голосов
/ 06 июля 2011

Вы уже должны использовать SSL для установки аутентификации.

Затем вы можете использовать тот же токен, который вы получили после аутентификации, в качестве секретного хэша для шифрования / дешифрования данных туда и обратно для этого соединения до тех пор, пока оно не станет недействительным.

Если системы должным образом заблокированы (внутренние), вы можете пропустить SSL для передачи зашифрованных данных, если вам нужна большая скорость (если исходный токен генерируется по SSL и система знает, какой IP-адрес назначен токену / etc) .

0 голосов
/ 20 октября 2015

Насколько я понял, у вас есть существующий код на месте.Чтобы сделать это проще, я покажу вам простой пример и то, как все работает с кодом ниже.Не стесняйтесь использовать только те части, которые вам нужны (что должно быть довольно просто).

То, как вы создали свое приложение, прекрасно работает с сеансами на стороне сервера.

Под кодомниже я приведу дополнительные пояснения и ссылки на ресурсы, которые помогут вам лучше понять код, протестировать и отладить ваше приложение.

$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;

Как вы можете видеть в коде, вы можетеопределить несколько безопасных шифров, но только один параметр версии SSL.Я бы не использовал ничего раньше, чем TLS 1.1.Любая более ранняя версия SSL уязвима для атаки.Начните с самого безопасного TLS 1.2 и проверьте, работает ли ваше приложение (обычно у вас не должно быть никаких проблем. Если у вас возникают какие-либо проблемы с подключением, попробуйте TLS 1.1. TLS версии 1.1 также является уязвимым, единственным безопасным (на данный момент,пока они не обнаружат какую-либо уязвимость) - это TLS 1.2.

Если безопасность является высшим приоритетом, используйте самую высокую доступную версию TLS (TLS1.2). Совместимость с клиентами не является вашей проблемой, когда существует ответственность за безопасность поставщика услуг.

Некоторые другие параметры cURL для просмотра:

Проверены шифрыСильный список Qualys SSL Labs (2014) и слабые шифры были удалены. Не стесняйтесь добавлять / удалять любые шифры.

  1. Прежде чем принять решение, взгляните на Qualys проектов SSL Labs о безопасности.
  2. Ознакомьтесь с этой статьей SSL Labs об идеальной секретности пересылки и передовых методах.
  3. Проверьте своиклиент (веб-браузер) для любых уязвимостей с помощью веб-инструмента SSL Labs .Это даст вам представление о том, на что обращать внимание и что нужно улучшить и обезопасить на вашем сервере и в приложении.
  4. Протестируйте свой веб-сайт / веб-службу с помощью SSL-лаборатории Qualys SSL .

Уязвимости и атаки: Longjam, FREAK, POODLE, вы называете это!Кто знает, какие еще атаки или уязвимости не обнаружены?Да!Все они влияют на ваш выбор соединения SSL / TLS.

Возможные параметры CURLOPT_SSLVERSION можно найти на официальной странице cURL: http://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.html

Вот также хорошее руководство OWASP для созданиябезопасный слой вокруг вашего приложения.

OWASP и Qualys SSL Labs - отличные ресурсы для начала.Я бы даже провел некоторое исследование по cURL и OpenSSL, чтобы ознакомиться со слабыми сторонами, возможными вариантами безопасности и лучшими практиками.

Существуют точки безопасности, которые я не упоминаю и которых не хватает, но мы не можем охватить все.

Если у вас есть какие-либо вопросы, я буду рядом, чтобы ответить, если смогу.

0 голосов
/ 06 июля 2011

Это может быть слишком элементарно для вашей ситуации, поскольку я ничего не знаю о Silverlight, но как насчет получения SSL-сертификата для вашего веб-API? Как и при создании вашего API, доступ к нему только осуществляется по протоколу https: // вместо http: //. Это зашифрует все, что передается между клиентом и сервером.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...