File tree Expand file tree Collapse file tree 6 files changed +82
-1
lines changed
Expand file tree Collapse file tree 6 files changed +82
-1
lines changed Original file line number Diff line number Diff line change 1+ ##### v1.5.0
2+
3+ * Support for nonce for either style-src, script-src, or both
4+ * Lower case headers for improved performance
5+ * Support for referrer-policy
6+ * Allow CSRF cookie options to be set
7+ * Bugfix: return to suppress promise warning
8+
9+
110##### v1.4.1
211
312* Bugfix: typo in ` nosniff ` header
Original file line number Diff line number Diff line change @@ -77,6 +77,8 @@ Furthermore, parsers must be registered before lusca.
7777 * ` [{ "img-src": "'self' http:" }, "block-all-mixed-content"] `
7878* ` options.reportOnly ` Boolean - Enable report only mode.
7979* ` options.reportUri ` String - URI where to send the report data
80+ * ` options.styleNonce ` Boolean - Enable nonce for inline style-src, access from ` req.locals.nonce `
81+ * ` options.scriptNonce ` Boolean - Enable nonce for inline script-src, access from ` req.locals.nonce `
8082
8183Enables [ Content Security Policy] ( https://www.owasp.org/index.php/Content_Security_Policy ) (CSP) headers.
8284
Original file line number Diff line number Diff line change 1616│ limitations under the License. │
1717\*───────────────────────────────────────────────────────────────────────────*/
1818'use strict' ;
19+ var crypto = require ( 'crypto' ) ;
1920
2021
2122/**
2425 */
2526var lusca = module . exports = function ( options ) {
2627 var headers = [ ] ;
28+ var nonce ;
2729
2830 if ( options ) {
2931 Object . keys ( lusca ) . forEach ( function ( key ) {
3032 var config = options [ key ] ;
33+ if ( key === "csp" && options [ key ] && ( options [ key ] [ 'styleNonce' ] || options [ key ] [ 'scriptNonce' ] ) ) {
34+ nonce = true ;
35+ }
3136
3237 if ( config ) {
3338 headers . push ( lusca [ key ] ( config ) ) ;
@@ -38,14 +43,20 @@ var lusca = module.exports = function (options) {
3843 return function lusca ( req , res , next ) {
3944 var chain = next ;
4045
46+ if ( nonce ) {
47+ Object . defineProperty ( res . locals , 'nonce' , {
48+ value : crypto . pseudoRandomBytes ( 36 ) . toString ( 'base64' ) ,
49+ enumerable : true
50+ } ) ;
51+ }
4152 headers . forEach ( function ( header ) {
4253 chain = ( function ( next ) {
4354 return function ( err ) {
4455 if ( err ) {
4556 next ( err ) ;
4657 return ;
4758 }
48- header ( req , res , next ) ;
59+ return header ( req , res , next ) ;
4960 } ;
5061 } ( chain ) ) ;
5162 } ) ;
Original file line number Diff line number Diff line change @@ -9,6 +9,8 @@ module.exports = function (options) {
99 var policyRules = options && options . policy ,
1010 isReportOnly = options && options . reportOnly ,
1111 reportUri = options && options . reportUri ,
12+ styleNonce = options && options . styleNonce ,
13+ scriptNonce = options && options . scriptNonce ,
1214 value , name ;
1315
1416 name = 'content-security-policy' ;
@@ -27,6 +29,22 @@ module.exports = function (options) {
2729 }
2830
2931 return function csp ( req , res , next ) {
32+ if ( styleNonce ) {
33+ if ( value . match ( / s t y l e - s r c ' n o n c e - .{ 48 } ' / ) ) {
34+ value = value . replace ( value . match ( / ' s t y l e - s r c n o n c e - .{ 48 } ' / ) , 'style-src \'nonce-' + res . locals . nonce + '\'' ) ;
35+ }
36+ else {
37+ value = value . replace ( 'style-src' , 'style-src \'nonce-' + res . locals . nonce + '\'' ) ;
38+ }
39+ }
40+ if ( scriptNonce ) {
41+ if ( value . match ( / s c r i p t - s r c ' n o n c e - .{ 48 } ' / ) ) {
42+ value = value . replace ( value . match ( / s c r i p t - s r c ' n o n c e - .{ 48 } ' / ) [ 0 ] , 'script-src \'nonce-' + res . locals . nonce + '\'' ) ;
43+ }
44+ else {
45+ value = value . replace ( 'script-src' , 'script-src \'nonce-' + res . locals . nonce + '\'' ) ;
46+ }
47+ }
3048 res . header ( name , value ) ;
3149 next ( ) ;
3250 } ;
Original file line number Diff line number Diff line change @@ -94,4 +94,34 @@ describe('CSP', function () {
9494 . expect ( 200 , done ) ;
9595 } ) ;
9696 } ) ;
97+
98+ describe ( 'nonce checks' , function ( ) {
99+ it ( 'no nonce specified' , function ( done ) {
100+ var config = require ( './mocks/config/cspEnforce' ) ,
101+ app = mock ( { csp : config } ) ;
102+
103+ app . get ( '/' , function ( req , res ) {
104+ res . status ( 200 ) . end ( ) ;
105+ } ) ;
106+
107+ request ( app )
108+ . get ( '/' )
109+ . expect ( 'Content-Security-Policy' , / ^ (? ! .* n o n c e ) .* $ / )
110+ . expect ( 200 , done ) ;
111+ } ) ;
112+
113+ it ( 'nonce specified' , function ( done ) {
114+ var config = require ( './mocks/config/nonce' ) ,
115+ app = mock ( { csp : config } ) ;
116+
117+ app . get ( '/' , function ( req , res ) {
118+ res . status ( 200 ) . end ( ) ;
119+ } ) ;
120+
121+ request ( app )
122+ . get ( '/' )
123+ . expect ( 'Content-Security-Policy' , / n o n c e / )
124+ . expect ( 200 , done ) ;
125+ } ) ;
126+ } ) ;
97127} ) ;
Original file line number Diff line number Diff line change 1+ 'use strict' ;
2+
3+
4+ module . exports = {
5+ reportOnly : false ,
6+ scriptNonce : true ,
7+ policy : {
8+ "default-src" : "*" ,
9+ "script-src" : "'unsafe-inline"
10+ }
11+ } ;
You can’t perform that action at this time.
0 commit comments