Skip to content

Commit 7c66d44

Browse files
author
Peter Bengtsson
authored
static assets should not use csrf (Set-Cookie) (#23357)
* static assets should not use csrf (Set-Cookie) Part of #1316 * move setFastlySurrogateKey up too
1 parent b91d720 commit 7c66d44

2 files changed

Lines changed: 50 additions & 28 deletions

File tree

middleware/index.js

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,39 @@ export default function (app) {
8181
app.use(datadog)
8282
}
8383

84+
// Must appear before static assets and all other requests
85+
// otherwise we won't be able to benefit from that functionality
86+
// for static assets as well.
87+
app.use(setFastlySurrogateKey)
88+
89+
// Must come before `csrf` otherwise you get a Set-Cookie on successful
90+
// asset requests. And it can come before `rateLimit` because if it's a
91+
// 200 OK, the rate limiting won't matter anyway.
92+
// archivedEnterpriseVersionsAssets must come before static/assets
93+
app.use(
94+
asyncMiddleware(
95+
instrument(archivedEnterpriseVersionsAssets, './archived-enterprise-versions-assets')
96+
)
97+
)
98+
app.use(
99+
'/assets',
100+
express.static('assets', {
101+
index: false,
102+
etag: false,
103+
lastModified: false,
104+
maxAge: '1 day', // Relatively short in case we update images
105+
})
106+
)
107+
app.use(
108+
'/public',
109+
express.static('data/graphql', {
110+
index: false,
111+
etag: false,
112+
lastModified: false,
113+
maxAge: '7 days', // A bit longer since releases are more sparse
114+
})
115+
)
116+
84117
// *** Early exits ***
85118
// Don't use the proxy's IP, use the requester's for rate limiting
86119
// See https://expressjs.com/en/guide/behind-proxies.html
@@ -110,7 +143,6 @@ export default function (app) {
110143
app.set('etag', false) // We will manage our own ETags if desired
111144
app.use(compression())
112145
app.use(disableCachingOnSafari)
113-
app.use(setFastlySurrogateKey)
114146
app.use(catchBadAcceptLanguage)
115147

116148
// *** Config and context for redirects ***
@@ -136,31 +168,6 @@ export default function (app) {
136168
app.use(haltOnDroppedConnection)
137169

138170
// *** Rendering, 2xx responses ***
139-
// I largely ordered these by use frequency
140-
// archivedEnterpriseVersionsAssets must come before static/assets
141-
app.use(
142-
asyncMiddleware(
143-
instrument(archivedEnterpriseVersionsAssets, './archived-enterprise-versions-assets')
144-
)
145-
)
146-
app.use(
147-
'/assets',
148-
express.static('assets', {
149-
index: false,
150-
etag: false,
151-
lastModified: false,
152-
maxAge: '1 day', // Relatively short in case we update images
153-
})
154-
)
155-
app.use(
156-
'/public',
157-
express.static('data/graphql', {
158-
index: false,
159-
etag: false,
160-
lastModified: false,
161-
maxAge: '7 days', // A bit longer since releases are more sparse
162-
})
163-
)
164171
app.use('/events', asyncMiddleware(instrument(events, './events')))
165172
app.use('/search', asyncMiddleware(instrument(search, './search')))
166173

tests/rendering/server.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -956,11 +956,26 @@ describe('?json query param for context debugging', () => {
956956

957957
describe('static routes', () => {
958958
it('serves content from the /assets directory', async () => {
959-
expect((await get('/assets/images/site/be-social.gif')).statusCode).toBe(200)
959+
const res = await get('/assets/images/site/be-social.gif')
960+
expect(res.statusCode).toBe(200)
961+
expect(res.headers['cache-control']).toContain('public')
962+
expect(res.headers['cache-control']).toMatch(/max-age=\d+/)
963+
// Because static assets shouldn't use CSRF and thus shouldn't
964+
// be setting a cookie.
965+
expect(res.headers['set-cookie']).toBeUndefined()
966+
// The "Surrogate-Key" header is set so we can do smart invalidation
967+
// in the Fastly CDN. This needs to be available for static assets too.
968+
expect(res.headers['surrogate-key']).toBeTruthy()
960969
})
961970

962971
it('serves schema files from the /data/graphql directory at /public', async () => {
963-
expect((await get('/public/schema.docs.graphql')).statusCode).toBe(200)
972+
const res = await get('/public/schema.docs.graphql')
973+
expect(res.statusCode).toBe(200)
974+
expect(res.headers['cache-control']).toContain('public')
975+
expect(res.headers['cache-control']).toMatch(/max-age=\d+/)
976+
// Because static assets shouldn't use CSRF and thus shouldn't
977+
// be setting a cookie.
978+
expect(res.headers['set-cookie']).toBeUndefined()
964979
expect(
965980
(await get(`/public/ghes-${enterpriseServerReleases.latest}/schema.docs-enterprise.graphql`))
966981
.statusCode

0 commit comments

Comments
 (0)