Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expire hsts cache & invert ssl redirect #6

Open
ccfontes opened this issue Nov 17, 2015 · 7 comments
Open

expire hsts cache & invert ssl redirect #6

ccfontes opened this issue Nov 17, 2015 · 7 comments

Comments

@ccfontes
Copy link

Say I use wrap-ssl-redirect for the case the user loads a website using http to get him redirected to the https version. I also use wrap-hsts for the second time and so on, so that when the user tries to access the website using http, it is immediately converted to https before sending the request.

Then it happens that my new ssl certificate is unsecure and browsers start complaining. Many former users are still accessing the website via https, which will take them to a security page first. To make matters worse, even if they do use http, the link will immediately be converted to https due to the hsts cache.

To solve these issues, I came up with this:

(defn- build-hsts-expire-header
  [{:keys [include-subdomains?] :or {include-subdomains? true}}]
  (str "max-age=" 0
       (if include-subdomains? "; includeSubDomains")))

(defn wrap-expire-hsts
  {:arglists '([handler] [handler options])}
  [handler & [{:as options}]]
  (fn [request]
    (-> (handler request)
        (resp/header "Strict-Transport-Security" (build-hsts-expire-header options)))))

(defn- http-url [url-string port]
  (let [url (java.net.URL. url-string)]
    (str (java.net.URL. "http" (.getHost url) (or port 80) (.getFile url)))))

(defn- get-request? [{method :request-method}]
  (or (= method :head)
      (= method :get)))

(defn wrap-insecure-redirect
  "Middleware that redirects any HTTPS request to the equivalent HTTP URL.
  Accepts the following options:
  :port - the port to use for redirects, defaults to 80."
  {:arglists '([handler] [handler options])}
  [handler & [{:keys [port]}]]
  (fn [request]
    (if (= (:scheme request) :https)
      (-> (resp/redirect (http-url (req/request-url request) port))
          (resp/status   (if (get-request? request) 301 307)))
      (handler request))))

Is there an easier way to solve this? If not, how about including this use case in ring-ssl along the lines of undoing ssl?

@weavejester
Copy link
Member

I'm not quite sure what your code is supposed to be doing. Your wrap-expire-hsts function is the same as wrap-hsts, and I'm uncertain what wrap-unsecure-redirect has to do with your problem.

(Also, it's "insecure" rather than "unsecure" - unfortunately English is pretty inconsistent that way.)

@ccfontes
Copy link
Author

Thanks. I just fixed the lexical error, and added a missing helper function.

wrap-insecure-redirect serves to make a permanent redirect from https to http. The purpose is that from then on, typing site.com will get http:// appended, instead of https://.

@ccfontes
Copy link
Author

Furthermore,

If I used wrap-hsts and wrap-ssl-redirect before, and then replace that with just wrap-insecure-redirect, after the first request, typing https://site.com will be rewritten to http://site.com in Chrome, Firefox and Safari, but it has to be in same browser session. If I restart the browser session, Firefox won't rewrite https to http on first request, but Safari will (didn't test with Chrome this time). Finally, when using also wrap-expire-hsts, Firefox will rewrite https to http after the browser session is restarted, on first request. I think this is enough to prove both functions utility.

@ccfontes
Copy link
Author

I mean "first request" above as a request made after the request that was used by wrap-expire-hsts or wrap-expire-hsts the first time, independent of the browser session.

@weavejester
Copy link
Member

I still don't see the point of wrap-expire-hsts, as it's the same as wrap-hsts but with the :max-age option set to zero:

(wrap-hsts handler {:max-age 0})

I'm also not sure what the benefit of wrap-insecure-redirect is. It seems like something you'd almost never need to do! Under what circumstances would you want to permanently redirect HTTPS to HTTP?

@ccfontes
Copy link
Author

Thanks, I didn't remember max-age was an option . To be clear, that code is just to give an example for the use case. In no way I mean that specific implementation should go to the repo. :)

Circumstances

I create an SSL certificate with StartSSL™.

Then there are two circumstances:

  1. The next year I need to renew it, but in the middle of the process I make a mistake and produce a broken certificate. That mistake is expensive, because I can't renew the certificate without revoking it. Revoking it comes with a fee. So then I'm stuck with a broken SSL certificate, and browsers start complaining about it to users. The browsers give alerts or take them to security pages to tell them how dangerous my website is. Users become bothered with the prompts, or just fearful, and visits to my website go down. If I just use http, then when they try to access the website, they will think it's down.
  2. The next year I think the renewal process it's too much trouble for my specific website. So I decide to go http, but now everyone is linking to my website with https links and so they will fail to access it.

It's not just about the previous users cache. Also, all google links in search results are https at the moment. And google takes it's time. Maybe some days, maybe weeks.. to update the results to http.

It's true that majors players in the browser market are making a huge effort to make https everywhere. But one thing is vision, another thing is reality and choice. We still have to wait for letsencrypt.org to become public on 3 of December, and even then, we don't know for sure what the market's response will be.

@bheesham
Copy link

Seems like the market response was very positive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants