We have a custom built program that needs authenticated/encrypted communication between a client and a server[both in Python].
We are doing an overhaul from custom written Diffie-Hellman+AES to RSA+AES in a non-orthodox way. So I would be very interested in comments about my idea.
Prequisites: Klient has a 128bit RegistrationKey which needs to remain a secret during the authentication - this key is also the only shared secret between the server and client.
Client contacts the server over an insecure channel and asks the servers RSA PubKey
Client then queries the server:
[pseudocode follows]
RegistrationKey = "1dbe665ac7a944beb67f106f779e890b"
clientname = "foobar"
randomkey = random(bits=128)
rsa_cp = RSA(key=pubkey, data=randomkey+clientname)
aes_cp = AES(key=RegistrationKey, data=RegistrationKey+rsa_cp)
send(aes_cp)
3. Server then responds:
[pseudocode follows]
# Server decrypts the data and sees if it has a valid RegistrationKey, if it does...
clientuuid = random(bits=128)
sharedkey = random(bits=128)
rsa_cp = RSA(key=privkey, data=clientuuid+sharedkey)
aes_cp = AES(key=randomkey[got from client], data= rsa_cp)
send(aes_cp)
Now both sides know the "clientuuid", "sharedkey" which the client can use later to authenticate itself. The method above should be secure even when the attacker learns the regkey later since he would have to crack the RSA key AND man-in-the-middle attacks(on RSA) should stop the auth. from completing correctly.
The only possible attack method I see would be the case where the attacker knows the regkey AND can alter the traffic during the authentication. Am i correct?
I really want to hear your ides on what to add/remove from this method and If you know a much better way to do this kind of exchange.
PS! We are currently using Diffie-Hellman(my own lib, so it probably has flaws) and we have tried TLSv1.2 with PreSharedKeys(didn't work for some reason) and we are CONSTRICTED to http protocols since we need to do this in django. And because we are doing this in http we try to keep the request/answer count as low as possible(no sessions would be the best) - 1 would be the best :)
If you have any questions about the specifics, please ask.
So, you crypto/security geeks, please give me a helping hand :)
Don't re-invent the wheal, use HTTPS.
The server can issue certificates to the client and store them in the Database. Clients can be distributed with the server's self-signed certificate for verification. The server can verify clients by using Apache's HTTPS Environment Variables.
No. Use SSL. Reinventing cryptosystems is a bad idea.
What you can easily do is set up a reverse proxy. Run your Django app on a higher port (e.g., 8080) and set it to respond only to connections from the loopback address (127.0.0.1). Run the reverse proxy on port 443 (standard HTTPS port) and proxy all requests to the Django app. But setup the reverse proxy with the site's certificate and have it be an SSL endpoint. The proxied requests going to the Django app would then just be "regular old" HTTP, not HTTPS.
Apache Mod_Proxy
NginX as a Reverse Proxy
I don't think RegistrationKey adds any real security.
It needs more nonces (against replay attacks).
It needs more padding (or else the messages are small and thus easy to decrypt).
An algorithm can be proven to be secure, you may want to do this.
Most flaws in crypto are in the implementation, not in the algorithm (timing attacks, for example).
Related
I am trying to achieve secure TLS communication between my private Twisted client and my private Twisted server over the Internet, using my own cryptographic keys.
By "secure", I mean I want to make sure my client is indeed talking to my server, and my server is indeed talking to my client, without the risk of a man-in-the-middle attack. I reckon this is possible thanks to the TLS support in Twisted but I am a bit lost and would really appreciate some guidance please.
Thus far we have done something like this, using a shared secret password at the protocol level:
# client:
from twisted.internet import ssl
reactor.connectSSL(
host=ip_server,
port=port_server,
factory=MyClientFactory(),
contextFactory=ssl.ClientContextFactory()
)
# server:
factory = MyServerProtocolFactory()
context = ssl.DefaultOpenSSLContextFactory('keys/private.key', 'keys/selfsigned.crt')
reactor.listenSSL(port_server, factory, context)
This approach runs, but, as you can see, only the server has a private key and certificate. In other words, a man-in-the-middle can pretend being our server's IP, and read the secret password from our client.
Can you help me understand why the client doesn't seem to require any kind of secret key in this code, and how to replace this by a secure approach please? Thanks!
... only the server has a private key. In other words, a man-in-the-middle can pretend being our server's IP, and read the secret password from our client.
That's not how TLS works.
The server certificate and the matching private key is not used to encrypt the data, it is used to authenticate the server against the client to make sure that the client does not talk to a man in the middle. This authentication protects the key exchange, which is used to create symmetric keys for the encryption is both directions. So the application data are protected, even if only the server has certificate and key - provided that the client properly validates the certificate.
This works with both self-signed certificates and certificates issued by a publicly trusted CA. But with self-signed one needs to distribute the certificate or its fingerprint to the client before doing the TLS connection, since otherwise the client cannot properly validate the certificate from the server since it does not know what to expect.
But again, the client needs to properly validate the certificate. Your client does not since ClientContextFactory does not provide a context which validates certificates by default. Use instead optionsForClientTLS - see How to validate the SSL server certificate in twisted SSL client.
I'm about to use Python.requests to get data from my own online api to my local pc. My api requires authentication which for now is done trough simply posting user/pass:
params = {'user': 'username', 'pass':'password'}
requests.post(url, params=params)
Are this requests safe or is it going to allow a middle-man to capture that user/pass?
P.S My api is using a letsencrypt ssl certificate. Python version 3.7.0
this has nothing to do with the python-requests package, but with the HTTP (and HTTPS) protocols. HTTP is plain-text so anyone that manages to sniff your packets can read the content (hence the username/password pair in clear text). HTTPS uses strong encryption, so even someone sniffing your traffic will have a hard-time deciphering it - no encryption scheme is 100% safe of course but decrypting SSL traffic is currently way too costly even for the NSA.
IOW, what will make your requests "safe" is the use of the HTTPS protocol, not which python (or not python) package you use to write your client code.
Use the HTTPS protocol and it's safe provided you have a valid SSL certificate on your api. If you still feel paranoid/insecure, you can implement end-to-end encryption using an existing algorithm or create your custom algorithm either.
I have already implemented SSL communication where client application verifies the identity of the SSL server application using flask. Now I want SSL server application to verify the identity of the SSL-client application. Is it possible with flask ? How do I verify client certificate ? During first handshake client is sending CSR and in response I am sending back certificate signed by Self Signed CA certificate.
But I am not yet clear how the client will be verified by server while next communication. Is there any callback for cert verification. Link on Google groups says its not possible to have ssl authentication on Flask. in order to do this one need to use webserver like apache,ngnix. Is this the only way to authenticate client ?
There is one more thing that I want to achieve that I need to identify each client based on their certificate. is that even possible with flask.
my question could be naive as I am not yet much familiar to flask
Disclaimer
Before I start I would note #Emanuel Ey's comment. That you would want to consider if this was being done on a production or development server first. For example; if you are using Apache WebServer the HTTPS component can be done from Apache. The only thing you would do differently is pass through the certificate details as options and your server app would then verify the serial number within the app itself.
It is Possible
But it the way it is possible is not considered good programming practice. Unfortunately, it's not accessible from flask.request and not possible with the Flask package. However, Flask uses Werkzeug and it is possible by patching the werkzeug.serving package where will be writing your main Flask code. It is not recommended because you may want to update Flask or Werkzeug later and your patch might break and need to be re-factored. i.e. from 0.9 to 1.0.
This provides a solution without using a web server. But I would recommend the web server/environment variable combo. It is cleaner and comparatively good practice.
I have done some testing to see if this is easy to implement. I was able to confirm that this method can work using the latest development codebase 'Werkzeug-0.10_devdev_20141223-py2.7'.
You'll probably want to verify of the serial number (seed number) found in each certificate (and maybe even some other variables). As you may know, the serial is unique to each certificate and is determined during the certificate generation process by you on the server side. It helps to store this along with the clients record and certificate information (where appropriate) in order to verify client certificate serial number later on. Note: It may require alterations between hex and base 10 decimal.
Werkzeug dev_2014122
What I did was to add in the following options to the werkzeug.serving.BaseWSGIServer.__init__ call to wrap_socket().
Use these;
server_side=True, ca_certs= '/etc/apache2/ssl/ca.pem', cert_reqs=ssl.CERT_REQUIRED
ca_certs: Use this to verify against, this is the CA cert used to generate the client certificates)
ssl.CERT_REQUIRED: require client certificate verification against ca_certs
Note: If the client certificate is does not pass initial verification you will not be able to fetch the client certificate. It will be None.
Then in my Flask test class I patched verify_request
where
def verify_request(self, request, client_address):
cert = request.getpeercert(True)
raw = decoder.decode(cert)[0]
print "Serial Number of your certificate is: % " % str(raw[0][1])
# todo: do checks & if serial no is ok then return true
return True
werkzeug.serving.BaseWSGIServer.verify_request = verify_request
This proved it is possible but you'll probably want to investigate the request handlers of the HTTPServer class that the BaseWSGIServer inherits to find a better way to do a call back or override.
Werkzeug 0.9.X
If you are using Werkzeug 0.9.X I'm assuming you are using the import from OpenSSL import SSL. see code snippet here. I have not tested this.
Some of the calls you may be interested in for this version would be;
- Context.set_verify(mode, callback)
- Connection.get_peer_certificate()
Clarification
What I do not understand is your reference to sending a CSR during the first handshake. If this is your process of client certificate generation you may want to rethink how you do this in the context of your system and environment. If I could have some more information I could comment further..
Also, 'handshake' in an SSL/TLS context generally refers to the action of creating the secure connection in the first place using an existing certificate. Immediately after handshaking, loosely speaking, a connection is established.
I'm trying to set up a server and client in python where the server authenticates clients using SSL with certificates. There are a lot of examples of SSL certificates online, but everything I've found has the server providing a certificate to the client and the client checking it. I need the server to ensure that the client has the authority to connect to the server. I understand how to generate and send certificates and the basics of how they work. I would type out my code, but my client/server without SSL is working fine and I've been referencing this for SSL. The client/server example at the bottom of that page summarizes my understanding of SSL certs in python.
I realize this isn't much to go on, but if someone could explain the basic modifications to that example to have the server authenticate the client instead of the other way around, that would be awesome. Alternatively, a link to an example or even just some socket methods to investigate would be very helpful. Let me know if more information is needed. I don't mean to be vague and promise I've spent all morning looking for info myself :).
Edit: I'm trying to stick to the basic ssl library. Aka "import ssl".
You would use SSLSocket.getpeercert to get the certificate. The client would need to specify a key and certificate when wrapping the socket just like the server side. On the server side, you will also need to pass ca_certs="path_to_ca_cert_file" and probably also want to specify cert_reqs=CERT_REQUIRED (see. args for ssl.wrap_socket.
In addition to this, it sounds like you might be looking to do certificate based client authentication/authorization? This is a simple matter of using getpeercert to get the client certificate and accessing fields within the certificate to use in a normal authentication path (i.e. Common Name == User Id)
Not really sure what your question refers, however you can see SSL in Python, other resource for SSL in Python, Validating SSL, get SSL Certificate information and you probably found other good links.
I am little stumped: I have a simple messenger client program (pure python, sockets), and I wanted to add proxy support (http/s, socks), however I am a little confused on how to go about it. I am assuming that the connection on the socket level will be done to the proxy server, at which point the headers should contain a CONNECT + destination IP (of the chat server) and authentication, (if proxy requires so), however the rest is a little beyond me. How is the subsequent connection handled, specifically the reading/writing, etc...
Are there any guides on proxy support implementation for socket based (tcp) programming in Python?
Thank you
Maybe use something like SocksiPy which does all the protocol details for you and would let you connect through a SOCKS proxy as you would without it?
It is pretty simple - after you send the HTTP request: CONNECT example.com:1234 HTTP/1.0\r\nHost: example.com:1234\r\n<additional headers incl. authentication>\r\n\r\n, the server responds with HTTP/1.0 200 Connection established\r\n\r\n and then (after the double line ends) you can communicate just as you would communicate with example.com port 1234 without the proxy (as I understand you already have the client-server communication part done).
Have a look at stunnel.
Stunnel can allow you to secure
non-SSL aware daemons and protocols
(like POP, IMAP, LDAP, etc) by having
Stunnel provide the encryption,
requiring no changes to the daemon's
code