Azure / azure-storage-cpp

Microsoft Azure Storage Client Library for C++
http://azure.github.io/azure-storage-cpp
Apache License 2.0
131 stars 147 forks source link

Ability to specify customized trust store, TLS 1.2 enforcement, Cipher Suites enforcement/Hardening, Validate Certificate Revocation List is needed #357

Open majumd opened 4 years ago

majumd commented 4 years ago

Hi, The client library could specify to use the https endpoint to connect to Azure. However it uses the OS certificate store for the root certificates. We would like to use the client library and would like to have few enhancements in view of security. 1) We would like to have ability to specify a custom certificate store instead of using the default OS certificate store. 2) We would like to disable use of SSLv2, SSLv3, TLS1.0 TLS 1.1 and only enforce TLS 1.2 3) We would like to enforce a list of hardened TLS cipher suites. 4) We would like to have ability to specify the revocation list so that revoked certificates are not used for SSL connections.

Could you please tell whether these feature requests could be done?

Jinming-Hu commented 4 years ago

Hi @majumd , TLS version enforcement shouldn't be done from client side. Client side provides a maximum version it supports, and server side picks one. So Client cannot enforce a high version while reject a lower version. (Update on 3/21/2022: TLS version enforcement can be done and should be done from client-side, to avoid MITM TLS downgrade attack)

It can be done in configuration of a storage account on Azure Portal.

Screen Shot 2020-07-05 at 12 12 12 PM

Jinming-Hu commented 4 years ago

For other features you've mentioned, they are all platform specific. As a client library we want to be portable, so we cannot do it in our library. But we do expose an API with which you can get the connection handle every time a new connection is established. Check it here. You can specify a callback function, and do those platform specific stuff in that callback function.

majumd commented 4 years ago

Thanks for the response. What would be the way to initialize m_ssl_context_callback and m_native_session_handle_options_callback of class _operation_context so that they would apply for any connections made using the client library?

Do we need to define a static function in class operation_context similar to set_default_log_level() to set the callback at global scope? or is there any other method to define the callback function in a global scope?

Jinming-Hu commented 4 years ago

@majumd Every function that's going to make a network connection has at least one overload that will accept an operation context in parameter. For example, for blob container create function, we have a overload here. It accepts an operation_context.

So what you need to do is

  1. define a callback function, the signature of which should be void(web::http::client::native_handle)
  2. initialize an operation_context and call operation_context::set_native_session_handle_options_callback with the callback function you just defined in 1.
  3. Call the APIs with this operation_context

In this way, every time a connection is established, the callback will get called and in that callback function you can do something you want to the connection handle.

majumd commented 4 years ago

The below sample program validates whether the container exists given connection string. The sample program would use default operation_context object which would not have the custom callback functions set. azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string); azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client(); azure::storage::cloud_blob_container container = blob_client.get_container_reference(_XPLATSTR("my-sample-container")); container.exists();

To make the plugin go through custom callback handler, the below function needs to be called. exists_async(const blob_request_options& options, operation_context context) function.

This leaves a chance of programming error where a developer might call a function without an operation_context and it might not abide by the security considerations a client program should have enforced.

It would be nice to enforce the security considerations on whatever function call is made by the developer. An ability where the client program could set the default callback function at the start of the program and all service function calls uses the same operation context defaults would have been nice.

Jinming-Hu commented 4 years ago

To make the plugin go through custom callback handler, the below function needs to be called. exists_async(const blob_request_options& options, operation_context context) function.

If you want sync version API, you can also call exists(const blob_request_options& options, operation_context context)

Jinming-Hu commented 4 years ago

This leaves a chance of programming error where a developer might call a function without an operation_context and it might not abide by the security considerations a client program should have enforced.

It would be nice to enforce the security considerations on whatever function call is made by the developer. An ability where the client program could set the default callback function at the start of the program and all service function calls uses the same operation context defaults would have been nice.

I think what you need here is a method to change the global configuration. As far as I know, storage sdk doesn't provide this functionality. Since storage sdk uses cpprestsdk as HTTP client, maybe there's something you can do with cpprest. Anyway, that's already out of the scope of this sdk, maybe you want to create an issue in https://github.com/microsoft/cpprestsdk?

hielkedehaan commented 3 years ago

I do not understand how this all works but when I set my server side on TLS 1.2 my client refuses to connect. is there something wrong with the pc settings or do I need to add a line in my client code to say it uses TLS 1.2?

Jinming-Hu commented 3 years ago

@hielkedehaan Does it work if you set a lower TLS version on your server side? If it does, maybe it's because underlying HTTP client doesn't support TLS 1.2. Can you share the environment your application is running in?

hielkedehaan commented 3 years ago

Yes a lower TLS version works only I do not seem to be able to get the client communicating when I set it to 1.2. Thank you for the quick response.

Jinming-Hu commented 2 years ago

This is an old issue, but just in case anybody else will be directed here by search engine, this is how to enfore TLS1.2 on Windows:

azure::storage::operation_context context;
context.set_native_session_handle_options_callback([](web::http::client::native_handle h) {
    auto tlsOption = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
    WinHttpSetOption(
        h,
        WINHTTP_OPTION_SECURE_PROTOCOLS,
        &tlsOption,
        sizeof(tlsOption));
});
b.download_text(azure::storage::access_condition(), azure::storage::blob_request_options(), context);

You need to include winhttp.h and link to winhttp.lib to use this function.