问题
Running on Windows Azure Websites, I want to use ssl via the default *.azurewebsites.net certificate. It works without doing anything, but http is also available for every destination, not just https. How do I force a redirect from http to https? Normally I could just do something like:
var https = require('https');
...
var options = {
key: fs.readFileSync('path.key'),
cert: fs.readFileSync('path.crt')
};
...
https.createServer(options, app)
but since I don't know anything about the *.azurewebsites.net certificate, such as its path, that's not going to work.
How do I redirect all or some requests to https?
回答1:
In web.config
, add the following rule before any other rule that has stopProcessing="true"
.
<rule name="RedirecttoHTTPS">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{URL}" pattern="/$" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="https://{SERVER_NAME}/{R:1}" redirectType="SeeOther" />
</rule>
You can also just use the normal http.createServer(app)
for production if you want to the *.azurewebsite.net wildcard certificate.
References:
- How to require SSL in IIS7 and Azure with Rewrite
- URL Rewrite Module Configuration Reference
回答2:
The accepted answer wasn't working for me, it would just display a blank page, this one:
<!-- Redirect all traffic to SSL -->
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
From https://gist.github.com/tstpierre/afec7eb409aebe0bf3d1 works perfectly though.
回答3:
If you prefer to validate that your node app is receiving secure traffic from within the node app, Richard Astbury has a solution on his blog.
tl;dr: IIS is acting as a proxy to the node app, and adds an "x-arr-ssl" header to requests if they were served over HTTPS. You can also use the "x-site-deployment-id" header to validate whether or not your app is currently running in azure. The middleware ends up like so:
function requireHTTPS(req, res, next) {
var isAzure = req.get('x-site-deployment-id'),
isSsl = req.get('x-arr-ssl');
if (isAzure && !isSsl) {
return res.redirect('https://' + req.get('host') + req.url);
}
next();
}
app.use(requireHTTPS);
While you're at it, it's a good idea to add HSTS, too:
var helmet = require('helmet');
function requireHTTPS(req, res, next) {
var isAzure = req.get('x-site-deployment-id'),
isSsl = req.get('x-arr-ssl');
if (isAzure && !isSsl) {
return res.redirect('https://' + req.get('host') + req.url);
}
next();
}
app.use(requireHTTPS);
app.use(helmet.hsts({
maxAge: 10886400000, // Must be at least 18 weeks to be approved by Google
includeSubdomains: true, // Must be enabled to be approved by Google
preload: true
}));
Of course you can always do this in tandem with the web.config answer.
回答4:
Since it sounds like Azure Websites is acting as a reverse proxy in your case, this approch may work for you:
If you can get the protocol from the following, it should help you:
req.headers['x-forwarded-proto']
This should give you the http or https you need to key on on order to do a redirect if it is not valid for the resource you are serving.
I use code like the following to redirect any time I get a request (for an html file or site root for example). I put all the files I want to be secure in a /secure directory to make it easy to know what should and should not be ssl:
protocol = req.headers['x-forwarded-proto'];
if ((req.url.lastIndexOf('.html') == (req.url.length - 5)) || (req.url.slice(-1) == '/')) {
if (protocol == 'http') {
if (req.url.indexOf('/secure/') == 0) {
console.log('Non ssl request made to secure resource: ' + req.url);
console.log('Redirecting to https://' + site_host_name + req.url);
res.writeHead(301,
{Location: 'https://' + site_host_name + req.url}
);
res.end();
return;
} else {
next();
return;
}
} else {
if (req.url.indexOf('/secure/') != 0) {
console.log('ssl request made for non-secure resource: ' + req.url);
console.log('Redirecting to http://' + site_host_name + req.url);
res.writeHead(301,
{Location: 'http://' + site_host_name + req.url}
);
res.end();
return;
} else {
next();
return;
}
}
}
来源:https://stackoverflow.com/questions/20578283/how-do-you-force-express-on-node-js-in-azure-websites-to-use-https