How to authenticate if auth headers are not supported on client-side? - authentication

TL;DR: How to authenticate against NGINX if auth headers are not supported on client side?
I am building an IoT-related project using NGINX as a reverse proxy for the server side services and 1NCE as the LTE carrier for the mobile devices. All traffic is authenticated based on HTTPBasicAuth over SSL-encrypted connections and handling "normal" requests works as desired.
As mobile service might be interrupted and the Internet connection might be lost, I want to send SMS for critical status reports and alarm notifications. 1NCE supports SMS mobile originated SMS (MO SMS) which are handled by the 1NCE's internal infrastructure and forwarded to a configurable API endpoint. So, MO SMS are not delivered to a specified phone, but forwarded via an API request which I need to process on my side.
According to 1NCE's SMS documentation and in consultation with their customer support, SMS forwarding does not support any authentication headers. SMS forwarding can only be done by specifying an HTTPS URL (including the desired API endpoint) and a port. The incoming SMS is then wrapped in a request to the given URL and sent in the request body.
I want to add authentication to the SMS forwarding endpoint (receiving forwarded SMS on my side) as well and am currently wondering about how I could achieve this. NGINX supports authentication on subrequest which could be used to evaluate incoming requests by an internal service. So my first idea was to add some credentials to each SMS (as I am also responsible for the SMS sending part of the code on the mobile devices, I could implement whatever is needed) and check those credentials with an internal service called by NGINX's subrequest. However, this does not seem to be doable. According to this SO question GET requests are used for the internal subrequests hence any body of the incoming POST request is discarded. Therefore, the credentials of the forwarded SMS would also be not available to my internal auth service. Extending NGINX's auth capabilities by writing an custom Lua-based plugin was my second idea, but this does not only seem to be not feasible but is also not supported by the NGINX instance I am using (Lua modules are disabled, switching to openresty seems to be a big thing).
My last idea would be to forward all incoming requests to a Python web service (written in Flask, other services I am using are also written in Flask) and parsing the forwarded SMS in Python. Based on the result of the credential evaluation I could return an 401/Unauthorized status code if credentials provided in the SMS (which is part of the request body) are invalid and process the request otherwise. However, I think that this approach is quite ugly as all incoming requests need to be passed to Flask and invalid requests are not rejected at the level of my Reverse Proxy.
Do you have any ideas about how to approach this issue? What would be a considerable approach with regards to "best practises"? Can I extend NGINX in a way to solve this or should I completely drop NGINX in favor of a "better" proxy?

Related

If a server calls an API, what IP will the API detect?

Consider the case where there exists a simple client-server web application where the client sends requests to the server. If the server sends a request to an external API, what IP and header values will be detected by the API? The ones of the client that first send the request to the server, or the ones of the server?
Only the actual IP that makes the request will be visible to the API. So if there is a chain of requests, only the last request IP will be accessible to the receiving party.

How can I authenticate a websocket connection where client and server reside on seperate domains?

I'm currently playing around with SignalR and websockets. From my research, it seems, as websockets do not support custom headers, there's basically only two ways to authenticate a websocket connection during token based authentication.
1) Passing the token in the query string
2) Storing the token in a cookie which then gets passed to the server when WithCredentials is set to true
The first method isn't great practice - even through websocket communication is encrypted, query strings may be logged by servers etc.
The second method I have got working on my local machine but it doesn't work once deployed because my client and server reside on different domains. So basically, I have an Angular site that has one domain (eg. client.com) and a WebAPI site that alls CORS with a completely different domain (eg. server.com). On my browser, if I'm on client.com, I cannot set a cookie that gets sent to server.com on a request.
What is a good way to authenticate websockets when client and server sit on different domains?
The WebSocket Protocol specification doesn't specify any particular way for authentication. You need to perform the authentication during the handshake phase and for that you can use any HTTP authentication mechanism like Basic, Digest, etc.
Further you could look into JWT token based authentication. Angular app can store the token in local storage and send it as a Transport header during the handshake request to the server. If the token is invalid, server can terminate the WebSocket connection upgrade request and the Angular app can re-direct the user to login page.

How do I prevent a user from accessing a server's API directly and instead force them to use the UI?

More of a theoretical question, but I'm really curious!
I have a two part application:
Apache server hosting my UI
Back-end that services all http requests from the UI
The apache service proxies all http requests from the UI to the server. So, if the user is reasonably adept, they can reverse engineer our API by inspecting the calls in the browser's developer tools.
Thus, how do I prevent a user from using the server API directly and instead force them to use the UI?
The server can't determine whether a call came from the UI or not because a user can make a call to myapp.com/apache-proxy/blah/blah/blah from outside of the UI, apache will get the request and forward it to the server, which will have no idea it's not coming from a UI.
The option I see is to inject a header into the request from the UI, that indicates the origin of the request as the UI. This seems ripe for exploitation though.
To me, this is more of a networking question since its something I'd resolve at the network level. If you run your backend application in a private network (or on a public network with firewall rules) you can configure the backend host to only accept communication from your Apache server.
That way the end-user can't connect directly to the API, since its not accessible to the public. Only the allowed Apache server will be able to communicate with the backend API. That way the Apache server acts as an intermediary between the end-user (client side) and the backend API server.
An example diagram from AWS.
You could make the backend server require connections to be authenticated before accepting any requests from them. Then make it so only the Apache server can successfully authenticate in a way that end users cannot replicate. For example, by using SSL/TLS between Apache and the backend, where the backend requires client certificates to be used, and then issue Apache a private certificate that the backend will accept. Then end users will not be able to authenticate with the backend directly.

How to procect API from man in the middle attacks

I will build a cross platform application (WP8, IOS, Android) and those apps will use
my server to make API requests.
My server also will call different type of APIs (google, facebook, etc) and return some results.
And application owner does not has to be logged in to make those calls.
If there is man in the middle, he can track api calls and use it for his own usage drain my quota against api services I am using.
I only want phone who has application be able to make those calls.
What would be the best way to detect api calls to my server should come from my application?
You can use SSL to prevent man in the middle attacks but there really isn't a way that you can be 100% certain that you are communicating with your application.. You can make it harder to do by requiring some sort of access token or using custom encryption but if somebody can decompile your app they can do whatever they want.
In your specific case you should use HTTPS and in the client, not only check that you are using an HTTPS connection, but that the certificate presented by the server and its certificate chain are the ones you expect.
If you fail to do so, you could still perform a MITM attack. For example:
The MITM proxy could act as the client to the server and use an HTTP connection to serve the contents to the real client.
The MITM proxy could act as the client to the server and use a self-signed SSL certificate to present the real client an HTTPS connection.

Can WSO2 ESB play the role of an HTTP(S) proxy for mediating incoming REST API requests?

Background:
I'm trying to use WSO2 ESB within a corporate setting to provide authenticated access to underlying REST API backend providers located either within the enterprise, or on the internet.
My goal is to selectively grant access, e.g. to REST API provider P1 only to REST client C1 and to to REST API provider P2 only to REST client C2.
Using WSO2 ESB with the "<api>" as described into http://wso2.com/library/articles/2012/10/implementing-restful-services-wso2-esb/ seems to impose to redefine every resource, which can be very large and error prone for complex APIs (e.g. vmware vcloud director REST API https://www.vmware.com/support/vcd/doc/rest-api-doc-1.5-html/landing-user_operations.html)
Using the WSO2 ESB "<proxy>", as described into
https://docs.wso2.org/display/ESB481/Using+REST+with+a+Proxy+Service#UsingRESTwithaProxyService-RESTClientandRESTService ("REST Client and REST Service") imposes that the URIs exposed to HTTP clients will be modified modified w.r.t. to the original backed uri. Typical proxy URIs will be of the following form with the services prefix and a specific port http://<wso2_host>:8280/services/CustomerServiceProxy/customers/123
While having modified exposed URIs is fine when the client can be controlled (typically an in house custom REST API). It is problematic when the REST API is an industry standard and the client is an SDK, or an off-the-shelf application which is outside of the control of WSO2 users (e.g. AWS S3 API, or vmware vcloud director REST API)
In addition, some custom clients/SDKs may verify server-side SSL certificates against a public key embedded into the SDK/client.
The usual solution to preserve the HTTP REST API as-is and add some authentication on top of it is to expose the API through an HTTP proxy (possibly authenticating clients through HTTP proxy authentication), i.e. client send a CONNECT request prior to sending their original request. This preserves the full URIs and also the SSL certificates.
Question:
Is there a way to have WSO2 ESB play the role of an HTTP(S) proxy for mediating incoming REST API requests, preserving original URIs and server SSL certificates ?
I'm thinking about a new "<http-proxy>" syntax, I haven't yet spotted. I.e. it would listen to http://<wso2_host>:3128/ and respond to CONNECT requests. The mediation would then have the ability to accept or not the CONNECT depending on the CONNECT request inputs (proxy authentication, requested host), and other http transport headers). Once the CONNECT request is granted, it might even be possible to act on subsequent individual proxified requests
Best specs describing the CONNECT behavior seem https://datatracker.ietf.org/doc/html/draft-luotonen-web-proxy-tunneling-01 (1999 draft that seems adopted) and https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p2-semantics-22#page-29 proposed standard.
For HTTPS URI, there might be limited ability within the WSO2 mediation: the HTTP request is SSL encrypted and only the domain can be known if SNI (Server Name Indication) is specified in the request. At least this would enable to grant/deny some host names to a set of clients depending on proxy authentication.
You may wish to try the <property name="preserveProcessedHeaders" value="true"/> in your <inSequence>. This property will pass all security headers through the proxy. I'm not sure about server certificates.
Here is an example of that property in use:
https://docs.wso2.org/display/ESB481/Sample+153%3A+Routing+Messages+that+Arrive+to+a+Proxy+Service+without+Processing+Security+Headers
I hope tlevel for API usehat helps. You may also want to look into the wso2 API manager, which lets you selectively grant access to APIs.