336

Is there any way to detect HTTP or HTTPS and then force usage of HTTPS with JavaScript?

I have some codes for detecting the HTTP or HTTPS but I can't force it to use https: .

I'm using the window.location.protocol property to set whatever the site is to https: then refresh the page to hopefully reload a new https'ed URL loaded into the browser.

if (window.location.protocol != "https:") {
   window.location.protocol = "https:";
   window.location.reload();
}
Steven Penny
  • 82,115
  • 47
  • 308
  • 348
Registered User
  • 7,674
  • 8
  • 28
  • 39
  • 16
    This is far more reliably (and efficiently) handled server side. – Quentin Apr 05 '12 at 21:09
  • 3
    I think you are right. As an attacker using a MITM attack, I could just delete this code. So it offers only protection against passiv attacks. – ndevln Jan 20 '14 at 18:44
  • The detection part is a duplicate of [How can I use JavaScript on the client side to detect if the page was encrypted?](http://stackoverflow.com/questions/282444/how-can-i-use-javascript-on-the-client-side-to-detect-if-the-page-was-encrypted) from 2008. – Dan Dascalescu Jul 13 '15 at 21:35
  • 1
    @NeoDevlin a MITM attacker on http can replace a server side redirect as well – Alex Lehmann Mar 10 '17 at 23:50
  • 1
    Exactly. In 2018, there is no excuse not to use HSTS. This is the only safe way to force HTTPS. –  Mar 13 '18 at 10:10

13 Answers13

545

Try this

if (location.protocol !== 'https:') {
    location.replace(`https:${location.href.substring(location.protocol.length)}`);
}

location.href = blah adds this redirect to the browser history. If the user hits the back button, they will be redirected back to the the same page. It is better to use location.replace as it doesn't add this redirect to the browser history.

Nathan
  • 511
  • 2
  • 15
Soumya
  • 12,424
  • 6
  • 32
  • 46
  • 3
    Why `window` and not `document`? – webjay Dec 19 '13 at 16:16
  • 5
    @webjay see http://stackoverflow.com/a/2431375/228534 and http://stackoverflow.com/a/12098898/228534 – Soumya Dec 23 '13 at 13:36
  • 11
    Should the string comparison be `!==`? – Wes Turner Oct 12 '14 at 14:06
  • 5
    @WesTurner It shouldn't matter either way. They're both always going to be strings. If one was a number or a boolean, then it might make a difference. – Soumya Oct 14 '14 at 03:53
  • What about using location,protocol? Now a days everyone suggesting it. – Anees Sadeek Aug 08 '15 at 05:17
  • instead of doing substring you can just use window.location.hostname – Mandeep Janjua Sep 15 '15 at 20:57
  • 1
    I like to use: `if (window.location.protocol == "http") window.location.href = "https" + window.location.href.slice(4);` – daalbert Sep 13 '16 at 06:55
  • 1
    While this does work, it causes a page refresh upon entering the website for the first time. Not an elegant solution. – Robbie Smith Oct 26 '16 at 10:43
  • 1
    @daalbert you missed a colon. This works: `if (window.location.protocol === 'http:') { window.location.href = 'https:' + window.location.href.slice(5); }` – Zero3 Feb 22 '17 at 15:35
  • @Zero3: I haven't tested myself, but I would expect that since he left out the colon in both cases, it would come out to the same thing. After all, he left out the domain name, but that makes no difference because it is the same thing for both protocols. – zondo Mar 28 '17 at 02:54
  • 2
    @zondo I'm afraid that is not how string equality works. It checks whether both strings are completely identical. So when `window.location.protocol` is `http:`, it will not be equal to `http`, and thus the code does not work as intended. According to [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/protocol), then `window.location.protocol` includes the colon after the protocol name. Also note that the domain name is not stored in `window.location.protocol` at all, so it is not used in the comparison in any way. – Zero3 Mar 28 '17 at 14:53
  • 18
    `location.replace(url)` would be much better than `location.href = url` for this case. You don't want this redirection in the browser's history or the user hitting the back button just to get redirected again. – Francisco Zarabozo Jul 27 '18 at 17:36
  • 1
    Should this answer not be using `window.location.` instead of directly `location.` It's both clearer syntactically and safer incase location is locally overridden. See https://stackoverflow.com/questions/4709037/window-location-versus-just-location – redfox05 May 09 '20 at 16:18
66

Setting location.protocol navigates to a new URL. No need to parse/slice anything.

if (location.protocol !== "https:") {
  location.protocol = "https:";
}

Firefox 49 has a bug where https works but https: does not. Said to be fixed in Firefox 54.

sam
  • 35,828
  • 2
  • 38
  • 36
24

It is not good idea because you just temporary redirect user to https and browser doesn't save this redirect.

You describe task for web-server (apache, nginx etc) http 301, http 302

b1_
  • 2,002
  • 24
  • 37
  • 3
    agree. Forcing https on server is far more reliable – Hoàng Long Aug 17 '12 at 08:07
  • 3
    I could see it being used if preserving the hash value is important. It is not sent to the server and some browsers do not preserve it. – Jason Rice Oct 03 '13 at 00:22
  • Here's a link to Set Azure Web Site for https only ... http://blogs.msdn.com/b/benjaminperkins/archive/2014/01/07/https-only-on-windows-azure-web-sites.aspx – OzBob May 15 '15 at 01:55
  • 1
    Not necessarily true. There is a school of thought that 301 is the devil for caching reasons. http://getluky.net/2010/12/14/301-redirects-cannot-be-undon/ – fivedogit Mar 03 '16 at 15:03
  • 2
    While it's true that it's generally not a good idea to do this client side, this is not what was asked. And you do not show how to do it, hence this is not an answer. Also, in these days of static webpages, often there is no way to do this server side (think Github pages), meaning you have to do this on the client. Still, you can help improve the search by adding canonical link tags to avoid people hitting the non-ssl version. – oligofren Dec 28 '18 at 14:26
16

How about this?

if (window.location.protocol !== 'https:') {
    window.location = 'https://' + window.location.hostname + window.location.pathname + window.location.hash;
}

Ideally you'd do it on the server side, though.

keirog
  • 2,105
  • 1
  • 19
  • 17
15
if (location.protocol == 'http:')
  location.href = location.href.replace(/^http:/, 'https:')
Steven Penny
  • 82,115
  • 47
  • 308
  • 348
6

You should check this: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests

Add this meta tag to your index.html inside head

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Hope it helped.

Itay Ben Shmuel
  • 299
  • 3
  • 6
  • Much more elegant solution when you do not have control of the code being sun on the page (html from a db for instance). We had a gravatar insecure connection and this solved everything. – ransems Jun 25 '20 at 09:25
5

Not a Javascript way to answer this but if you use CloudFlare you can write page rules that redirect the user much faster to HTTPS and it's free. Looks like this in CloudFlare's Page Rules:

enter image description here

Mikeumus
  • 2,440
  • 5
  • 32
  • 54
  • I actually found this very useful, not for answering the question as framed, but for providing useful information about a possibly more reliable way for a SaaS service that does not offer always-on SSL. – MrMesees Apr 11 '16 at 09:07
3

You can do:

  <script type="text/javascript">        
        if (window.location.protocol != "https:") {
           window.location.protocol = "https";
        }
    </script>
Bhargav Rao
  • 41,091
  • 27
  • 112
  • 129
M.BRAHAM
  • 31
  • 2
1

Functional way

window.location.protocol === 'http:' && (location.href = location.href.replace(/^http:/, 'https:'));
1

I like the answers for this question. But to be creative, I would like to share one more way:

<script>if (document.URL.substring(0,5) == "http:") window.location.replace('https:' + document.URL.substring(5));</script>
Jade Hamel
  • 1,149
  • 1
  • 14
  • 29
1

The below code assumes that the variable 'str' contains your http://.... string. It checks to see if it is https and if true does nothing. However if it is http it replaces http with https.

if (str.indexOf('https') === -1) {
  str = str.replace('http', 'https')
}
Laymans Code
  • 62
  • 1
  • 6
  • 3
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Donald Duck Jun 20 '20 at 23:33
  • This answer is related to this question. https://stackoverflow.com/questions/11300906/check-if-a-string-starts-with-http-using-javascript/11300967 – javed Dec 30 '20 at 07:43
-1

Hi i used this solution works perfectly.No Need to check, just use https.

<script language="javascript" type="text/javascript">
document.location="https:" + window.location.href.substring(window.location.protocol.length, window.location.href.length);
</script>
cs95
  • 274,032
  • 76
  • 480
  • 537
-2

I have just had all the script variations tested by Pui Cdm, included answers above and many others using php, htaccess, server configuration, and Javascript, the results are that the script

<script type="text/javascript">        
function showProtocall() {
        if (window.location.protocol != "https") {
            window.location = "https://" + window.location.href.substring(window.location.protocol.length, window.location.href.length);
            window.location.reload();
        }
    }
    showProtocall();
</script> 

provided by vivek-srivastava works best and you can add further security in java script.

Tim Hutchison
  • 2,865
  • 5
  • 33
  • 67
Peter
  • 1