Ответ 1
Добавление адреса с указанным протоколом решило проблему для меня.
connectSources = ["'self'", "ws://localhost:3000"]
Я пытаюсь внедрить политики безопасности контента (CSP) на сервере node, и у меня возникают проблемы с настройкой socket.io. Похоже, я неправильно настроил connectSrc
в приведенном ниже коде. Может ли кто-нибудь предложить правильный способ создания шлема, чтобы браузерные сокеты разрешались браузером? Спасибо заранее!
Я использую модуль шлема для генерации CSP; ниже приведен код, который устанавливает CSP:
securitySetup = function(app) {
var connectSources, helmet, scriptSources, styleSources;
helmet = require("helmet");
app.use(helmet());
app.use(helmet.hidePoweredBy());
app.use(helmet.noSniff());
app.use(helmet.crossdomain());
scriptSources = ["'self'", "'unsafe-inline'", "'unsafe-eval'", "ajax.googleapis.com"];
styleSources = ["'self'", "'unsafe-inline'", "ajax.googleapis.com"];
connectSources = ["'self'"];
return app.use(helmet.contentSecurityPolicy({
defaultSrc: ["'self'"],
scriptSrc: scriptSources,
styleSrc: styleSources,
connectSrc: connectSources,
reportUri: '/report-violation',
reportOnly: false,
setAllHeaders: false,
safari5: false
}));
};
Это отлично работает для всего трафика HTTP/AJAX, но не работает для протокола ws://. Я получаю эту ошибку в хром-отладчике при подключении socket.io:
Refused to connect to 'ws://localhost:3000/socket.io/1/websocket/ubexeZHZiAHwAV53WQ7u' because it violates the following Content Security Policy directive: "connect-src 'self'".
Добавление адреса с указанным протоколом решило проблему для меня.
connectSources = ["'self'", "ws://localhost:3000"]
Тесное чтение Спецификации политики безопасности содержимого объясняет, почему 'self'
не работает:
'self'
соответствует запросам с тем же хостом, портом и схемой. Поскольку ваша исходная страница, загруженная схемой http://
или https://
, 'self'
не будет соответствовать соединениям с помощью ws://
.
Это делает 'self'
скорее бесполезным для соединений в сети. Если я что-то не хватает, я думаю, что это ошибка в спецификации.
вы можете использовать ws: или wss: как ключевое слово для websocket, здесь используется мой код
app.use(helmet.csp({
'default-src': ["'self'"],
'connect-src': [
"'self'" , "blob:",
'wss:',
'websocket.domain',
],
'font-src': ["'self'",'s3.amazonaws.com',"maxcdn.bootstrapcdn.com"],
'img-src': ["'self'", 'data:'],
'style-src': ["'self'","maxcdn.bootstrapcdn.com",'s3.amazonaws.com',"'unsafe-inline'"],
'script-src': ["'self'","'unsafe-inline'","'unsafe-eval'",'blob:'],
reportOnly: false,
setAllHeaders: false,
safari5: false
}))
с wss://websocket.domain является доменом для websocket, поэтому, если вы можете использовать его для localhost
Немного опоздал на вечеринку, но подумал, что я брошу что-то в микс по этой теме. @Ed4 совершенно прав, 'self'
действительно будет соответствовать только одному хосту, порту и схеме. Путь к нему состоит в том, чтобы включить его в одну или несколько форм:
connect-src: wss:
- разрешить соединение со всей схемой wss
- в основном любой веб-сокет (возможно, не идеальный)
connect-src: wss://yoursite.domain.com
- ограничить его конкретной конечной точкой. Это наиболее оптимально, но может быть ограничительным, если ваш поддомен изменяется между развертываниями (как это делает наш)
connect-src: wss://*.domain.com
- можно использовать подстановочные знаки, чтобы немного закрепить защиту. Это то, что мы делаем
TL; DR - используйте подстановочные знаки, чтобы сделать вещи более конкретными, не открывая себя ни на какие веб-сокеты там /
Обратитесь к этому отрывку от разработчиков Google:
Список источников в каждой директиве является гибким. Вы можете указать источники по схеме (data:, https:) или варьироваться в зависимости от имени узла (example.com, которое соответствует любому происхождению на этом хосте: любая схема, любой порт) до полного URI (https://example.com:443, который соответствует только HTTPS, only example.com и только порт 443). Подстановочные знаки принимаются, но только в виде схемы, порта или в самой левой позиции имени хоста:://.example.com: * будут соответствовать всем поддоменам example.com(но не самому example.com), используя любые схемы на любом порту.
https://developers.google.com/web/fundamentals/security/csp/
Здесь можно автоматически добавить текущий хост и порт в выражении (синтаксис es6):
import csp from 'helmet-csp';
app.use((req, res, next) => {
let wsSrc = (req.protocol === 'http' ? 'ws://' : 'wss://') + req.get('host');
csp({
connectSrc: ['\'self\'', wsSrc],
})(req, res, next);
});