在虚拟主机或安全中强制使用 SSL 时无限循环。yml/routing.yml

Infinite loop when forcing SSL either in vhost or in security.yml/routing.yml

我正在使用 Symphony 2.6 和 Nginx 1.4。这个问题已经被问过好几次了,但所有提供的答案或解决方案都不适合我。

我希望新的 Linux Counter Project 完全只有 SSL,但无论我是在 nginx 的 vhost 文件中设置重定向到端口 443,还是添加 required_channel https 到security.yml 或者如果我将 [https] 添加到 routing.yml,访问页面时一切都会导致无限循环。

尽管如此,SSL 工作正常。当从 vhost 文件中删除所有重定向以及从 security.yml 和 routing.yml 中删除 https 内容时,一切正常,您可以访问例如:https://www.linuxcounter.net/login 没有任何问题。

这是 vhost 文件没有强制 SSL:

server {
    listen 80;
    server_name www.linuxcounter.net api.linuxcounter.net linuxcounter.net;
    root /srv/www.linuxcounter.net/web;

    client_max_body_size 128M;

    location ~ ^/update\.php(/|$) {
        root /srv/www.linuxcounter.net/web;
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    }

    location / {
        try_files $uri /app.php$is_args$args;
    }

    location ~* ^/user/([0-9]+)\.html$ {
        root /srv/www.linuxcounter.net/web;
        rewrite /user/([0-9]+)\.html /user/ last;
        internal;
    }

    location ~* /(cert|mcert)/[0-9]+\.png$ {
    root /srv/www.linuxcounter.net/web;
        rewrite /(cert|mcert)/[0-9]+\.png /app.php last;
    expires -1;
    add_header Cache-Control private;
    }

    location ~ ^/app\.php(/|$) {
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    internal;
    }

    location ~* \.(js|jpg|png|css)$ {
        root /srv/www.linuxcounter.net/web;
        expires 30d;
    }

    error_log /LOGS/www.linuxcounter.net_error_log;
    access_log /LOGS/www.linuxcounter.net_access_log;
}

server {
    listen 443 default;
    server_name www.linuxcounter.net api.linuxcounter.net linuxcounter.net;
    root /srv/www.linuxcounter.net/web;

    client_max_body_size 128M;

    ssl                     on;
    ssl_certificate         /etc/nginx/ssl/2015-04-02-www.linuxcounter.net-cert-bundle.crt;
    ssl_certificate_key     /etc/nginx/ssl/2015-04-02-www.linuxcounter.net.key;

    ssl_session_timeout  5m;

    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers  RC4:HIGH:!aNULL:!MD5:!kEDH;
    ssl_prefer_server_ciphers   on;

    location ~ ^/update\.php(/|$) {
        root /srv/www.linuxcounter.net/web;
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
    }

    location / {
        try_files $uri /app.php$is_args$args;
    }

    location ~* /(cert|mcert)/[0-9]+\.png$ {
        root /srv/www.linuxcounter.net/web;
        rewrite /(cert|mcert)/[0-9]+\.png /app.php last;
        expires -1;
        add_header Cache-Control private;
    }

    location ~ ^/app\.php(/|$) {
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
        internal;
    }

    location ~* \.(js|jpg|png|css)$ {
        root /srv/www.linuxcounter.net/web;
        expires 30d;
    }

    error_log /LOGS/www.linuxcounter.net_error_log;
    access_log /LOGS/www.linuxcounter.net_access_log;
}

这是 vhost 文件 WITH 强制 SSL:

server {
    listen 80;
    server_name www.linuxcounter.net api.linuxcounter.net linuxcounter.net;
    root /srv/www.linuxcounter.net/web;
    return 301 https://www.linuxcounter.net$request_uri;
}

server {
    listen 443 ssl;
    server_name www.linuxcounter.net api.linuxcounter.net linuxcounter.net;
    root /srv/www.linuxcounter.net/web;

    client_max_body_size 512M;

    # ssl                     on;
    ssl_certificate         /etc/nginx/ssl/2015-04-02-www.linuxcounter.net-cert-bundle.crt;
    ssl_certificate_key     /etc/nginx/ssl/2015-04-02-www.linuxcounter.net.key;

    ssl_session_timeout  5m;
    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers  RC4:HIGH:!aNULL:!MD5:!kEDH;
    ssl_prefer_server_ciphers   on;

    location ~ ^/update\.php(/|$) {
        root /srv/www.linuxcounter.net/web;
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
    }

    location / {
        try_files $uri /app.php$is_args$args;
    }

    location ~* /(cert|mcert)/[0-9]+\.png$ {
        root /srv/www.linuxcounter.net/web;
        rewrite /(cert|mcert)/[0-9]+\.png /app.php last;
        expires -1;
        add_header Cache-Control private;
    }

    location ~ ^/app\.php(/|$) {
        fastcgi_pass php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
        internal;
    }

    location ~* \.(js|jpg|png|css)$ {
        root /srv/www.linuxcounter.net/web;
        expires 30d;
    }

    error_log /LOGS/www.linuxcounter.net_error_log;
    access_log /LOGS/www.linuxcounter.net_access_log;
}

一旦我将 vhost 文件替换为在端口 80 上重定向到 SSL 的文件,我就会在所有页面、链接或路由上得到无限循环。

因此,当浏览到 https://www.linuxcounter.net/login 时,/login 会重新加载 301 重定向 15 或 20 次,直到出现无限循环的错误消息。

但是对于第一个 vhost 文件,整个页面都可以毫无问题地使用 https://。

这是我的 routing.yml:

syw_front_main:
    resource: "@SywFrontMainBundle/Controller/"
    type:     annotation
    prefix:   /
    host:     %base_host%

fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"
    host:     %base_host%

easy_admin_bundle:
    resource: "@EasyAdminBundle/Controller/"
    type:     annotation
    prefix:   /admin
    host:     %base_host%

shtumi_useful:
    resource: '@ShtumiUsefulBundle/Resources/config/routing.xml'
    host:     %base_host%

blade_tester_light_news_bundle:
    resource: "@BladeTesterLightNewsBundle/Resources/config/routing.yml"
    prefix:   /news
    host:     %base_host%

syw_front_api:
    resource: "@SywFrontApiBundle/Controller/"
    type:     annotation
    prefix:   /
    host:     %api_host%

这是我的 security.yml:

# you can read more about security in the related section of the documentation
# http://symfony.com/doc/current/book/security.html
security:
    # http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    # http://symfony.com/doc/current/book/security.html#hierarchical-roles
    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email
        # in_memory:
        #     memory:
        #         users:
        #             user:  { password: userpass, roles: [ 'ROLE_USER' ] }
        #             admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }

    # the main part of the security, where you can set up firewalls
    # for specific sections of your app
    firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
            logout:       true
            anonymous:    true
            form_login:
                # login success redirecting options (read further below)
                always_use_default_target_path: false
                default_target_path:            fos_user_profile_show
                use_referer:                    true
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false
            form_login:
                # login success redirecting options (read further below)
                always_use_default_target_path: false
                default_target_path:            fos_user_profile_show
                use_referer:                    true

    # with these settings you can restrict or allow access for different parts
    # of your application based on roles, ip, host or methods
    # http://symfony.com/doc/current/cookbook/security/access_control.html
    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: /admin, role: ROLE_ADMIN }

对我来说一切似乎都很安静....

但我没有让它工作。

所以,我想要的是:

如果有人访问 http://*linuxcounter.net,那么他应该使用 301 重定向到 https://*linuxcounter.net

好的...经过几个小时的尝试和测试,我现在找到了一个不是很理想但有效的解决方案。

我现在只是在 Symfony 的 /app.php 顶部做一个重定向:

if ($_SERVER["HTTP_X_FORWARDED_PROTO"] == "http") {
    $redir = "Location: https://www.linuxcounter.net" . $_SERVER["REQUEST_URI"];
    header($redir);
    exit();
}

这有效并且不会产生任何无限循环。

你为什么不使用 symfony 呢?

  1. 在您的路由中将方案设置为 https(仅)http://symfony.com/doc/current/cookbook/routing/scheme.html(最简单的方法是在 routing.yml 中定义方案一次,然后导入例如 https_routing.yml 以继承方案对于所有路线)。
  2. 告诉 symfony 正确的头文件http://symfony.com/doc/current/components/http_foundation/trusting_proxies.html#configuring-header-names

我在许多项目中使用该设置。如果重定向在没有任何其他设置的情况下工作,现在我不是 100%,但如果不行,我明天可以查一下。我觉得应该可以,试试吧。