+34 688 911 123 hola@nubentos.com

by | Aug 22, 2019 | API Provider, Howtos | 0 comments

In the previous article, we saw that it was better to authenticate with username and password to access the endpoint published through https, than to access a completely open endpoint published by http, although few were those who knew the url. 

The configuration that we introduce in this third issue of the series, will save you from having to send the user data and the password in the communication with the endpoint.

Use a single-use key

An alternative to always using the same username and password, is the possibility of using a single-use encrypted key, which enables access to a resource. 

For this, we must use an algorithm that, based on some input data, generates this encrypted key. Both the connection client and the receiver must be able to validate that the key is correct. 

This mechanism is called authentication based on “Digest“.

05_Endpoint_Digest

 

The conversation between the client making the request and your endpoint begins with the request for access to the resource, to which the endpoint responds with an ‘Unauthorized’ message and parameters (realm, cnonce, qop) generated for this request, that the client must capture.

Next, another new request is generated, where a hash generated from several operations with the received parameters and other own ones are sent, such as username, nonce, uri, nc, being nc and nonce generated by the client uniquely for this request . 

Although it may seem more complex, actually there are few additional operations to other methods. But with this we managed to avoid a serious problem, which is that someone who has captured the traffic can make the same calls as an authorized customer, from their own application.

Even so, it continues to falter in certain aspects. In the end, we must store the password on the server where the endpoint is published and someone could get it.

How do we add a Digest-based authentication to your balancer?

We have to keep in mind that for nginx to allow this type of authentication, we must install a module that has not been fully validated: “ngx_http_auth_digest”, and the instructions are detailed in this link (2).

To make sure that the module is available in your installation, you can run the “nginx -V” command, as shown below.

# nginx -V

nginx version: nginx/1.10.1

built by gcc 6.3.0 (Alpine 6.3.0)

built with OpenSSL 1.0.2r  26 Feb 2019

TLS SNI support enabled

configure arguments: –with-http_ssl_module –with-http_gzip_static_module –prefix=/etc/nginx –http-log-path=/var/log/nginx/access.log –error-log-path=/var/log/nginx/error.log –sbin-path=/usr/local/sbin/nginx –add-module=../nginx-http-auth-digest

Now you can use the module, and to do so, edit the file load-balancer.conf and modify it as follows. 

http { 

   upstream applicationserver {

      server 192.168.0.10:8080; 

   }

 

server {

   listen 443 ssl;

   server_name api.apiprovider.com;

   ssl_certificate /etc/ssl/certs/api.apiprovider.crt;

   ssl_certificate_key /etc/ssl/certs/api.apiprovider.key;

   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

   ssl_ciphers HIGH:! aNULL:! MD5;

 

   auth_digest_user_file /opt/httpd/conf/passwd.digest;

   auth_digest_shm_size 4m;   

 

   location / api {

         proxy_pass http: // applicationserver / api;

         auth_digest realm;

         auth_digest_timeout 60s; 

         auth_digest_expires 10s; 

         auth_digest_replays 20; 

    }

  }

}

In this configuration we use a key file that we generate with the “htdigest” command by passing the resource, the user and the password.

htdigest -c password.digest <realm> <username>

Adding password for realm in realm username.

New password: <password>

Re-type new password: <password>

Unlike the .htpasswd file, you must add an entry for each resource in your API, if you want to control which resources will be accessed.

After reloading the configuration, you can perform a simple check by sending a request with the curl command.

curl -L -v –digest -uusername: password \

-X GET http://api.apiprovider.com/api/doctor/1 | jq

 

* Trying :: 1 …

* TCP_NODELAY set

* Connected to api.apiprovider.com (:: 1) port 443 (# 0)

* ALPN, offering h2

* ALPN, offering http / 1.1

* Cipher selection: ALL :! EXPORT:! EXPORT40:! EXPORT56:! ANULL:! LOW:! RC4: @STRENGTH

* successfully set certificate verify locations:

* CAfile: /etc/ssl/cert.pem

  CApath: none

* TLSv1.2 (OUT), TLS handshake , Client hello (1):

* TLSv1.2 (IN), TLS handshake, Server hello (2):

* TLSv1.2 (IN), TLS handshake, Certificate (11):

* TLSv1.2 (IN), TLS handshake , Server key exchange (12):

* TLSv1.2 (IN), TLS handshake, Server finished (14):

* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):

* TLSv1.2 (OUT) , TLS change cipher, Client hello (1):

* TLSv1.2 (OUT), TLS handshake, Finished (20):

* TLSv1.2 (IN), TLS change cipher, Client hello (1):

* TLSv1.2 ( IN), TLS handshake, Finished (20):

* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384

* ALPN, server accepted to use http / 1.1

* Server certificate:

* subject: C = ES; ST = ANDALUCIA; L = SEVILLA; O = falc0n.es; OU = Operations; CN = api.apiprovider.com

* start date: Aug 17 17:59:33 2019 GMT

* expire date: Jun 6 17:59:33 2022 GMT

* issuer: C = ES; ST = ANDALUCIA; L = SEVILLA; O = falc0n.es; OU = Operations; CN = api.apiprovider.com

* SSL certificate verify result: self signed certificate (18), continuing anyway.

* Server auth using Digest with user ‘username’

> GET / api / doctor / 1 HTTP / 1.1

> Host: api.apiprovider.com

> User-Agent: curl / 7.54.0

> Accept: * / *

>

<HTTP / 1.1 401 Unauthorized

<Server: nginx / 1.10.1

<Date: Sat, 17 Aug 2019 18:22:27 GMT

<Content-Type: text / html

<Content-Length: 195

<Connection: keep-alive

<WWW-Authenticate: Digest algorithm = “MD5”, qop = “auth”, realm = “medapp”, nonce = “1122e7865d5845e3”

<

* Ignoring the response-body

* Connection # 0 to host api.apiprovider.com left intact

* Issue another request to this URL : ‘https://api.apiprovider.com/api/doctor/1’

* Found bundle for host api.apiprovider.com: 0x7fb341f12c20 [can pipeline]

* Re-using existing connection! (# 0) with host api.apiprovider.com

* Connected to api.apiprovider.com (:: 1) port 443 (# 0)

* Server auth using Digest with user ‘username’

> GET / api / doctor / 1 HTTP / 1.1

> Host: api.apiprovider.com

> Authorization: Digest username = “username”, realm = “medapp”, nonce = “1122e7865d5845e3”, uri = “/ api / doctor / 1”, cnonce = “MDVjZDZkN2E4OGU3MGRmYTNmODJkNDBkNGEGkNDBkNGEGkNDBkNGEGkNDBkNGGE = = 00000001, qop = auth, response = “16ee2fb81e46dcb7a0d59e9d24c79fae”, algorithm = “MD5”

> User-Agent: curl / 7.54.0

> Accept: * / *

>

<HTTP / 1.1 200 OK

<Server: nginx / 1.10.1

< Date: Sat, 17 Aug 2019 18:22:28 GMT

<Content-Type: application / json

<Content-Length: 283

<Connection: keep-alive

<Authentication-Info: qop = “auth”, rspauth = “3d87fa3f31bc8cd08a378bea672d3fcd”, cnonce = “MDVjZDZkN2E4OGU3MGRmYTNmODJkNDBkNTIzYjljMGE =”, nc = 00000001

<Sl-Request-Valid: true

<Sl-Response-Valid: false

 

* Connection # 0 to host api.apiprovider.com left intact

{

  “category”: {

    “id 8: 47” ,

    “name”: “Ut cupidatat et aliqua”

  },

  “id”: 40824116,

  “name”: “doggie”,

  ” photoUrls “: [

    ” sunt aliqua voluptate ipsum “,

    ” eiusmod “

  ],

  ” status “:” resting “,

  ” tags “: [

    {

      ” id “: 47309272,

      ” name “:” cillum sit “

    }

  ]

}

And in Nubentos, How do we use the Digest based endpoint?

It’s as simple as selecting the corresponding option when adding it in the “Implement” tab.

Display “Show more options” and complete the “Endpoint Auth Type” field with the “Digest Auth” option, and enter the username and password.

04_Nubentos_Endpoint_DigestAuth

 

In this article, we have developed the basic configurations to secure access to an endpoint. There are other more complex and secure mechanisms such as OAuth2, OpenID and JWT, which require the use of specific frameworks for the development of the API, and a greater complexity of the necessary infrastructure. 

Nubentos provides these mechanisms by default to API consumers, therefore they are not necessary for the interconnection with the API provider’s endpoint.

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

Share This