… or how to deal with that pesky https mixed content error when using Flask on Windows.
Recognise this error message?
“Mixed content: The page at ‘https://…’ was loaded over https, but requested an insecure script. This request has been blocked; content must be served over https.”
Then you had better keep reading my friend.
Introduction
I’ve read enough of these tech blogs to know that the introductions are generally skipped, “Get me to the code, dammit!”. I appreciate that, but it won’t stop me from writing at least a little intro.
Please note that this is my first tech blog, so it might not be perfect, however I’ve found myself looking up this solution more than once and now I’m finally taking a page out of the “learning to code” manual and writing a post about it, so
a) I can refer back to it when I need to, and
b) I can hopefully help some other poor soul who has found themselves in the same predicament as me.
The problem
You are using IIS (Internet Information Services) on Windows (probably Windows Server) to host your site’s front-end. Your front-end makes API calls to a Python back-end to get its data, and sitting pretty in the middle is a little script using Flask to route your web requests.
This isn’t usually an issue at all, until you want to get all secure and start using certificates that is. When you do that, IIS will set up your front-end just fine, but what it won’t do is set your Flask application listening for requests to use SSL.
Why does it matter?
Well, if you’re using SSL on the front-end and then making requests to a non-SSL end-point, the clients web browser is going to throw back some errors about the site trying to request data from a non-secure source. This is a “Mixed Content” error, and depending on the information you’re trying to request, the browser may block your action completely.
The error will look similar to this:
The solution
Thankfully this solution is pretty straight forward. I’ll lay it out as simply as possible. If you follow all these steps in order, it shouldn’t take you more than ten minutes to solve the problem, assuming you have some basic knowledge of Python and are using Windows 10 or Windows Server and IIS, and already have a certificate. If you do not have a certificate, get one! You can use OpenSSL if you don’t want to buy one. This tutorial will not cover obtaining a certificate.
Step 1: You have a .pfx certificate
If your certificate is a .pem file with a key, you can ignore this step.
- Save your .pfx cert to the location where the flask application will be running. It is likely you will have a password with your .pfx file. If not, then ignore the password fields below.
- Install pyopenssl:
pip install pyopenssl
- Create a new .py file and copy in this code:
from OpenSSL.crypto import *passwd = '{YOUR_PASSWORD}'p12 = load_pkcs12(open('{CERTIFICATE_FILE_NAME}.pfx', 'rb').read(), passwd)#If you don't have a password, un-comment the below this:
#p12 = load_pkcs12(open('{CERTIFICATE_FILE_NAME}.pfx', 'rb').read())pkey = p12.get_privatekey()
open('pkey.pem', 'wb').write(dump_privatekey(FILETYPE_PEM, pkey))cert = p12.get_certificate()
open('cert.pem', 'wb').write(dump_certificate(FILETYPE_PEM,
cert))ca_certs = p12.get_ca_certificates()
ca_file = open('ca.pem', 'wb')
for ca in ca_certs:
ca_file.write(dump_certificate(FILETYPE_PEM, ca))
- Running this will create cert.pem and key.pem files which you will need in the next step
Step 2: Configure Flask
- Now watch out… this bit’s a doozy (jk, it’s super simple). In your Flask app, do the following:
from flask import Flask
from flask import request
#I'll cover CORS properly in the next tutorial
from flask_cors import CORS, cross_origincontext = ('cert.pem', 'pkey.pem')app = Flask(__name__) #Or whatever your app is called
CORS(app)... YOUR CODE HERE ...if __name__ == "__main__":
app.run(host='{YOUR_FQDN}', ssl_context=context, threaded=True, debug=True)
Note: The FQDN (fully qualified domain name) of the machine must include the domain (if any). For example, you might be using a machine on a company domain, so the FQDN would be something like:
thiscomputer.mycompany.com.
Or you could just have your own domain like: thisismycompany.com.
Whatever it is, just make sure you put it in the appropriate place above.
- Run the flask script and you should see that your front-end can now make SSL calls to your back-end without error! Great success.
In conclusion
I really hoped that solved the problem for you as it did for me.
If there’s anything that isn’t working or doesn’t make sense, please feel free to leave a comment. I’ll be happy to help.
