Passing credentials securely between two python applications - python

I'm looking for some recommendation for the following scenario. The solution that I need to build contains of:
Client component written in python that uses requests module to talk to proxy component described under 2. Client will send json data to proxy component and one of the things that we need to send are credentials that will be used between proxy and the final server.
"Proxy" component which is a python/Flask based application that
Uses https
Exposes API style access to receive JSON data from client described under point 1
Talks to the final server explained in step 3 by using requests module and requests_ntlm auth to authenticate to server.
Server which is a trusted but independent server not controlled by me, running apache or IIS.
The goal is to enable my client to talk to 3rd party server via my proxy flask/python app. Server expect client to perform ntlm authentication which is why proxy flask app uses requests_ntlm module to talk to the server.
However, proxy does not store client's credentials (and I don't need it that way). Ideally client would provide credentials on application start, send those credentials in JSON format to proxy and proxy would use it to obtain response from server after which credentials should be destroyed.
I wonder what kind of approach of exchanging credentials between client and proxy would be the best to use to maximize security and protect as much as one can be protected?
Approach I got so far would be:
Client is configured with an "API Key" which is for example 192 characters long.
When client talks to proxy, json request is generated in this fashion:
{ "instruction": "Do this on server",
"username": "johndoe",
"password": "password in clear text obtained with getpass for example"
"padding": "random string e.g. 128 - 1024 chars to make sure json payload is
always different no matter if all other fields are the same"
}
The entire json request is encrypted with the API KEY (open for suggestion about the recommended method for symmetrical encryption of data using a static key).
Padding is used to make sure json is always different when encrypted. It's a junk data that proxy expects but will ignore as it doesn't contain anything"
User/pass that client is sending is never stored anywhere. When user starts client python app, getpass module is used to get the password, put it into json, encrypt and send it over https and client application can delete variable used with getpass to read password input.
Proxy runs flask with https. Client trusts proxy's public key. Proxy also potentially can use address filter to limit who can talk to it in the direction client -> proxy (e.g. just trusted subnets)
Proxy expects json to be formatted correctly including having junk padding that's used to ensure randomness of the payload so it is always encrypted differently. Proxy will obtain instruction + user / pass
Proxy uses user / pass to open connection to server(s), authenticates with requests_ntlm using credentials provided by client and sends instruction to server (e.g. get me xyz.php?id=123)
Results from server are returned as json response from proxy to client using the same api key to encrypt json response + padding to randomise data. Proxy also deletes the variable used to store user/pass that was originally received from client in step 2.
Client will be able to read response by decrypting it with the api key stored in the config file or system variable.
What do you think about this approach and what are the areas one could improve security in this setup?
Thank you so much for any advice that you might have and for your time reading this long post.
M.

Related

can a client intercept or spoof the http response to modify the data for its own benefit?

I am developing an application that spends tokens to execute an operation.
each user has a limited amount of token and they will earn it as time goes by.
the number of tokens of each user is stored in a database as an integer, when the client application wants to execute the operation it sends an HTTP request to the server and on the server it checks the database if it has the necessary number of tokens, if the user has the necessary tokens, the server application subtracts the tokens from the database and sends an HTTP response like the following:
body_response:
{
"spent_tokens": [amount]
"can_execute": true
}
my question is if this is too insecure or not?, if it is possible to falsify the HTTP response?
and if it is unsure what other method I could use instead.
For the server application I am using python with flask and C# WPF in the client application making the HTTP requests with the HTTPClient standard library
thank you for your help
Yes, it is possible to spoof requests in both HTTP and HTTPS using tools such as Burp or curl. Not only is it possible, it is also extremely simple. Forging malicious HTTP/HTTPS requests is the bread and butter of any bad actor looking for flaws in your products. You should never trust data provided by the client. All sensitive state should be managed by a trusted server.

Authentication performed via Python script using an API access key

I create a client (plain python script) and server (flask app) in Python. I wonder how to perform simple authentication using a access key in Python. Authentication is for scripts - they are not real users (no registration required). The key will be assigned to the script during implementation.
Scenario 1:
Client sends message to server.
Server (flask app) reads token from Authorization header.
Server looks for the token in the database.
If server finds token in database it will authenticate the client.
The access token is explicitly passed to the client before sending messages and the client stores it in an environment variable.
Disadventages:
Tokens are not stored as hashes
Scenario 2:
Client sends message to server.
Server (flask app) reads token (jwt) from Authorization header.
Server decodes jwt token to: {'accessKeyId': 'fake_id', 'accessKey': 'fake_key'}
Server looks for the key in database by id.
If server finds row in db and key matches to decoded server will authenticate the client.
Adventages:
Keys are stored as hashes
The access token is explicitly passed to the client too. It requires:
create {'accessKeyId': 'fake_id', 'accessKey': 'fake_key'} object,
hash 'fake_key' (and save to server database),
generate jwt token (finally it will passed for client and it will be in environment variable).
Is the 2nd approach correct? How is this implemented in applications where the user gets an access key after registration in web app and can query the api (via REST) if the key is correct - sth like OpenWeatherMaps?
Edit:
I found out that I need to implement the KEY API mechanism. Are there any guides on how to do this in Flask/Python?
This decision is very situation dependent. I've read over your question and personally, I'd go with scenario 1. Unless of course, you don't want the script to know its own key? But that defeats the purpose in some ways because you'd need to refresh that key since JWTs have an expiry value and common practice is to have them short-lived. It seems like scenario 2 just adds unnecessary complexity.
You're still validating the token against the database in both scenarios. Unless you're encrypting the JWT then you'll still be enabling users of that JWT to view that same token. If you want to encrypt it, then go for it...but you've just created an encrypted token-like header which just adds more overhead because instead of just going token to database you're going to JWT -> decrypt -> Token -> database on every request and you'll still need some sort of access token for them to regenerate that JWT.
If you have special claims to give them and want to communicate that via JWT then that's valid, but you'll still need them to be short-lived and they have to refresh them.
tl;dr I'd go with scenario 1, it just seems based on the example to be the better solution in my opinion.
Not sure how much you've looked into JWT's but this may be a good place to start.

Active Directory authentication using ldap3 python, how to avoid clear text password

I know the below question has been asked multiple times and answer which i could find is that get SSL certs.
But how to go around it without SSL?
Here is the problem:
I have been implementing a Rest based API which authenticates a user with Active Directory.
Our security team has concern that passing plain text password from UI to API is a security risk.
But we are doing it because Active Directory needs password in plain text.
It just goes in JSON format in a POST request :
{"user":"uname","password":"password"}
Here is the AD auth code that i use from python ldap3 module.
s = Server(AD_SERVER, port=AD_PORT, use_ssl=True, get_info=ALL)
c = Connection(s, user=userName, password=password, authentication=NTLM)
c.bind()
So in above is there a way to send password in any hash or any encrypted format.
I am not sure if Active Directory or ldap3 supports such mechanism for this connection.
Any leads would be appreciated.
LDAP (or the python ldap3 package) supports a variety of authentication (bind) schemes. Some transfer the user's password to the server more or less in plaintext, while others (e.g. NTLM) use cryptography (to prove that the client represents the user, without transmitting the password to the server, e.g. like only transmitting a hash of the password convolved with a unique challenge that was issued to the client by the server).
The problem is that ldap3 tries to implement its own computation of the challenge-response. (This requires the password to be available to python, and is insecure and inconvenient.) Instead it should utilise the SSP Interface, i.e., pass the server's challenge to the client's operating system and let the OS compute the response for sending to the server. The OS will use the credentials from when the user logged on, and does not expose the password to python.
Similarly, the server application should not try to validate the response itself, but instead defer to the server's OS which forwards the challenge/response to the Domain Controller and returns whether they check out.
Some coding will be necessary, but here is an example of python ntlm sspi (applied for http instead of ldap), and there are also some demos in the pywin32 de facto standard library.
Probably however the correct way to do a restful application on a windows domain is to forget about ldap. Instead try to enable Integrated Windows Authentication on your webserver, or try something like flask-Kerberos or PyAuthenNTLM2.

Django rest Framework : encrypt response data

I am using Django rest Framework to build a REST API for one of my clients. The app provides some sensitive information such as passwords when the client asks for it through an API call.
Now, only authorized clients can access to the app and besides that, only authorized IP can connect.
But what if someone was listening in the middle of that connection ? He would see all the datas in clear.
Is there a way to encrypt those info, maybe with a password, and then decrypt it when it arrives ? (the client would have to update his app, but it's not a problem).
I was thinking maybe to create an "EncryptedResponse" instead of "Response" in my django app.
Thanks
If you don't have one already, purchase an SSL certificate and configure your site to load the API over HTTPS. That way the connection between the authorized client and your application would be encrypted which will prevent a man in the middle attack that you're describing.
If you're not going to load the API over HTTPS, then the authentication token, or API key, or whatever you're using to authenticate the client can also be intercepted.
However, if you're looking to stick to the encrypting the data route, I've found this guide that looks like it should help you be able do what you need to do:
http://gpiot.com/blog/encrypted-fields-pythondjango-keyczar/

Multiple backend servers accessible from a Flask server

I want to have a front-end server where my clients can connect, and depending on the client, be redirected (transparently) to another Flask application that will handle the specific client needs (eg. there can be different applications).
I also want to be able to add / remove / restart those backend clients whenever I want without killing the main server for the other clients.
I'd like the clients to:
not detect that there are other servers in the backend (the URL should be the same host)
not have to reenter their credentials when they are redirected to the other process
What would be the best approach?
The front-end server that you describe is essentially what is known as a reverse proxy.
The reverse proxy receives requests from clients and forwards them to a second line of internal servers that clients cannot reach directly. Typically the decision of which internal server to forward a request to is made based on some aspect of the request URL. For example, you can assign a different sub-domain to each internal application.
After the reverse proxy receives a response from the internal server it forwards it on to the client as if it was its own response. The existence of internal servers is not revealed to the client.
Solving authentication is simple, as long as all your internal servers share the same authentication mechanism and user database. Each request will come with authentication information. This could for example be a session cookie that was set by the login request, direct user credentials or some type of authentication token. In all cases you can validate logins in the same way in all your applications.
Nginx is a popular web server that works well as a reverse proxy.
Sounds like you want a single sign-on setup for a collection of service endpoints with a single entry point.
I would consider deploying all my services as Flask applications with no knowledge of how they are to be architected. All they know is all requests for resources need some kind of credentials associated with them. The manner you pass those credentials can vary. You can use something like the FAS Flask Auth Plugin to handle authentication. Or you can do something simpler like package the credentials provided to your entry service in the HTTP headers of the subsequent requests to other services. Flask.request.headers in your subsequent services will give you access to the right headers to pass to your authentication service.
There are a lot of ways you can go when it comes to details, but I think this general architecture should work for you.

Categories