Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
442 views
in Technique[技术] by (71.8m points)

php - Laravel 5 - htaccess HTTPS redirect on post routes doesn't work.

I have an application built with Laravel 5 acting as an API. I have the following in my .htaccess file to redirect all routes to https:

  RewriteEngine On

    # Force SSL
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

This works fine for the following:

https://example.com/route

but throws a MethodNotAllowedHttpException if i try to access it with http. It correctly redirects to https, but seems to be not correctly following with the POST request, since all my routes only allow POST.

Is there any way to fix this without changing my routes to allow GET as well?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In order to force https, your RewriteRule is required to force an external redirect. In the case of your rule, you're forcing a 301 redirect (R=301). Most browsers and clients are designed to automatically follow redirects, but they (incorrectly) do so with a GET request.

So, when a client sends a POST request with data to http://example.com/route, your server responds with a 301 redirect to https://example.com/route, and then the client makes a GET request without the data to the new URL. As you can see, you can't just change your routes to accept GET requests as well, because the data sent in the original POST request will be dropped.

One option would be to add a rewrite condition to not redirect POST requests:

# Force SSL
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} !=POST
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

However, this pretty much defeats the purpose of what you're attempting to accomplish. This whole concept is to force https everywhere. It would be silly to enforce it everywhere except when POSTing data to your application.

Another possible option would be to change your 301 redirect to a 307 redirect. Even though clients aren't supposed to change the request method for 301/302 redirects, most clients do due to ambiguity in the specs and existing functionality. Because of this, 307 was added with the specific idea that if this status code is used, the request method MUST NOT be changed. However, 307 is classified as a "temporary redirect", so it won't be cached and may affect your SEO. Additionally, this status was added in the HTTP/1.1 spec, so you may run into some clients that don't know how to process a 307.

Your best option is probably just to reject non-secure POST requests. Or, redirect them to an error page explaining you don't accept non-secure POST requests.

RewriteEngine On

# Forbid non-secure POSTs
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} =POST
RewriteRule ^ / [F,L]

# Force SSL
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...