bicf/yii2-security-headers

安全导向的头信息管理

安装数: 5,333

依赖: 0

建议者: 0

安全: 0

星标: 3

关注者: 4

分支: 2

开放问题: 0

类型:yii2-extension

v1.2.1 2022-04-20 09:59 UTC

This package is auto-updated.

Last update: 2024-09-20 14:58:30 UTC


README

简介

Yii2实现CSP - 内容安全策略

另请参阅MDN文档

安装

建议通过运行以下命令通过composer进行安装

composer require bicf/yii2-security-headers "*"

或者,您可以手动将以下内容添加到您的composer.json中的require部分

{
"bicf/yii2-security-headers": "*"
}

之后运行composer update

然后进行配置。

配置

版本1.1是模块实现。

在main.php中的securityHeader模块示例配置

[
    'bootstrap'=>[
        'securityHeader',
    ],
    'modules' => [
        'securityHeader' => [
            'class' => bicf\securityheaders\Module::class,
            'modules' => [
               'XContentTypeOptions'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderXContentTypeOptions',
                   'value' => 'nosniff',
               ],
               'XFrameOptions'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderXFrameOptions',
                   'value' => 'SAMEORIGIN',
               ],
               'AccessControlAllowMethods'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderAccessControlAllowMethods',
                   'value' => 'GET',
               ],
               'AccessControlAllowOrigin'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderAccessControlAllowOrigin',
                   'value' => 'https://api.example.com',
               ],
               'ContentSecurityPolicyAcl'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderContentSecurityPolicyAcl',
                   'enabled' => false,
                   'policies' => [
                       'default-src' => "'self'",
                       'frame-src'   => "'self' www.facebook.com www.youtube.com www.google.com",
                       'img-src'     => "'self' www.google-analytics.com",
                       'font-src'    => "'self' fonts.gstatic.com maxcdn.bootstrapcdn.com",
                       'media-src'   => "'self'",
                       'script-src'  => "'self' www.google-analytics.com",
                       'style-src'   => "'self' maxcdn.bootstrapcdn.com",
                        'connect-src' => "'self'",
                        'report-uri'  => "/report-csp-acl",
                    ],
                ],
                'ContentSecurityPolicyMonitor'=>[
                    'class' => 'bicf\securityheaders\modules\HeaderContentSecurityPolicyMonitor',
                    'policies' => [
                        'default-src' => "'self'",
                        'frame-src'   => "'self' www.facebook.com www.youtube.com www.google.com",
                        'img-src'     => "'self' www.google-analytics.com",
                        'font-src'    => "'self' fonts.gstatic.com maxcdn.bootstrapcdn.com",
                        'media-src'   => "'self'",
                        'script-src'  => "'self' www.google-analytics.com",
                        'style-src'   => "'self' maxcdn.bootstrapcdn.com",
                        'connect-src' => "'self'",
                        'report-uri'  => "/report-csp-acl",
                    ],
                ],
            ],
        ],
    ],

    'components' => [
        // components stuff
        // no need to add anything
    ],
]

内容安全策略头信息的Yii2集成

可能的集成方式

CSP可以通过签名或通过nonce令牌进行工作,请参阅

通过签名集成

只需简单地将签名添加到CSP配置中即可完成

示例

'style-src'   => "'sha256-aqNNdDLnnrDOnTNdkJpYlAxKVJtLt9CtFLklmInuUAE=' 'sha256-6fwFCXmgb6H4XQGajtDSVG3YuKmX3dT1NkX4+z510Og=' 'sha256-ZdHxw9eWtnxUb3mk6tBS+gIiVUPE3pGM470keHPDFlE='",

这种集成不需要对框架代码进行修补,但即使签名数量很少,也会占用空间并难以维护。

通过nonce令牌集成

这种集成需要在框架(\yii\helpers\BaseHtml)级别进行一些(小的)修补,以充分利用nonce令牌。一旦集成,默认启用的nonce功能就不需要维护,并且对头的占用空间更小

以下是支持nonce参数的透明方式修补BaseHtml函数的版本。

对Html::script辅助函数的修补

修补后的\yii\helpers\BaseHtml::script()

    public static function script($content, $options = [])
    {
        if(Yii::$app->response instanceof SecureRequestInterface){
            $behavior = Yii::$app->response->getBehavior(SecureRequestInterface::CSP_NONCE_BEHAVIOR);
            if($behavior != null){
                $options = array_merge(Yii::$app->response->getContentSecurityPolicyTokenArray(),$options );
            }
        }
        return static::tag('script', $content, $options);
    }

项目资产所需的script标签

修补后的\yii\helpers\BaseHtml::jsFile()

    public static function jsFile($url, $options = [])
    {
        $options['src'] = Url::to($url);
        if (isset($options['condition'])) {
            $condition = $options['condition'];
            unset($options['condition']);
            return self::wrapIntoCondition(static::tag('script', '', $options), $condition);
        }

        if(Yii::$app->response instanceof SecureRequestInterface){
            $behavior = Yii::$app->response->getBehavior('cspBehavior');
            if($behavior != null){
                $options = array_merge(Yii::$app->response->getContentSecurityPolicyTokenArray(),$options );
            }
        }

        return static::tag('script', '', $options);
    }

或者(更好)在jsFile函数内部调用script函数

    public static function jsFile($url, $options = [])
    {
        $options['src'] = Url::to($url);
        if (isset($options['condition'])) {
            $condition = $options['condition'];
            unset($options['condition']);
            return self::wrapIntoCondition(static::tag('script', '', $options), $condition);
        }

        return static::script('', $options);
    }

对视图中的<script>的不同处理方法

在视图中添加script标签

当在视图或控制器中显式使用<script>时,解决方案是直接通过以下方式在标签中添加nonce参数

Yii::$app->response->getContentSecurityPolicyTokenAttribute()

在视图内部

<script <?= Yii::$app->response->getContentSecurityPolicyTokenAttribute();?> >
    alert("test");
</script>

修补过的 \yii\debug\Module::renderToolbar 函数

    /**
     * Renders mini-toolbar at the end of page body.
     *
     * @param \yii\base\Event $event
     */
    public function renderToolbar($event)
    {
        if (!$this->checkAccess() || Yii::$app->getRequest()->getIsAjax()) {
            return;
        }

        /* @var $view View */
        $view = $event->sender;
        echo $view->renderDynamic('return Yii::$app->getModule("' . $this->id . '")->getToolbarHtml();');

        // echo is used in order to support cases where asset manager is not available
        echo '<style>' . $view->renderPhpFile(__DIR__ . '/assets/toolbar.css') . '</style>';
        echo '<script '.Yii::$app->response->getContentSecurityPolicyTokenAttribute().'>' . $view->renderPhpFile(__DIR__ . '/assets/toolbar.js') . '</script>';
    }

具体来说,这一行

echo '<script '.Yii::$app->response->getContentSecurityPolicyTokenAttribute().'>' . $view->renderPhpFile(__DIR__ . '/assets/toolbar.js') . '</script>';

运行时禁用

由于在调用render之前不会发送任何头信息,因此可以根据需要禁用一个或多个模块。  

public function actionIndex() {
    Yii::$app->getResponse()->modules['sample-module']->enabled=false;
    return $this->render("index");
}

旧版实现

这是旧版实现,通过扩展Request类来实现。

重要:如果您不设置配置,则不会发送任何头信息。

配置示例

[
    'components' => [
        'response' => [
            'class' => 'bicf\securityheaders\components\Response',
            'on afterPrepare' => ['bicf\securityheaders\components\Response','addSecurityHeaders'],
            'modules' => [
               'XContentTypeOptions'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderXContentTypeOptions',
                   'value' => 'nosniff',
               ],
               'AccessControlAllowMethods'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderAccessControlAllowMethods2',
                   'value' => 'GET',
               ],
               'AccessControlAllowOrigin'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderAccessControlAllowOrigin',
                   'value' => 'https://api.example.com',
               ],
               'ContentSecurityPolicyAcl'=>[
                   'class' => 'bicf\securityheaders\modules\HeaderContentSecurityPolicyAcl',
                   'enabled' => false,
                   'policies' => [
                       'default-src' => "'self'",
                       'frame-src'   => "'self' www.facebook.com www.youtube.com www.google.com",
                       'img-src'     => "'self' www.google-analytics.com",
                       'font-src'    => "'self' fonts.gstatic.com maxcdn.bootstrapcdn.com",
                       'media-src'   => "'self'",
                       'script-src'  => "'self' www.google-analytics.com",
                       'style-src'   => "'self' maxcdn.bootstrapcdn.com",
                        'connect-src' => "'self'",
                        'report-uri'  => "/report-csp-acl",
                    ],
                ],
                'ContentSecurityPolicyMonitor'=>[
                    'class' => 'bicf\securityheaders\modules\HeaderContentSecurityPolicyMonitor',
                    'policies' => [
                        'default-src' => "'self'",
                        'frame-src'   => "'self' www.facebook.com www.youtube.com www.google.com",
                        'img-src'     => "'self' www.google-analytics.com",
                        'font-src'    => "'self' fonts.gstatic.com maxcdn.bootstrapcdn.com",
                        'media-src'   => "'self'",
                        'script-src'  => "'self' www.google-analytics.com",
                        'style-src'   => "'self' maxcdn.bootstrapcdn.com",
                        'connect-src' => "'self'",
                        'report-uri'  => "/report-csp-acl",
                    ],
                ],
            ],
        ],
    ],
]