You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
My company has asked me to implement subresource integrity security in our Rails application. We're using shakapacker/webpack for our JavaScript assets (Sprockets is handling the bundling of our stylesheets and images). After researching how to do this, I came to learn that SRI isn't a first class feature of Shakapacker, however there is some information out there that helped me to roll my own solution.
config/webpack/webpack.config.js
const { generateWebpackConfig, merge } = require('shakapacker')
const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity')
const WebpackAssetsManifest = require('webpack-assets-manifest')
const webpackConfig = generateWebpackConfig()
const customConfig = {
output: {
// the following setting is required for SRI to work:
crossOriginLoading: "anonymous",
},
plugins: [
new SubresourceIntegrityPlugin(),
new WebpackAssetsManifest(
{
entrypoints: true,
integrity: true,
writeToDisk: true,
entrypointsUseAssets: true,
publicPath: true,
output: 'manifest.json'
}
)
]
}
// https://github.com/shakacode/shakapacker/discussions/85
const filteredPlugins = webpackConfig.plugins.filter((plugin) => !(plugin instanceof WebpackAssetsManifest))
webpackConfig.plugins = filteredPlugins
module.exports = merge(webpackConfig, customConfig)
# Based on https://github.com/rails/webpacker/issues/323#issuecomment-547616109
# rubocop:disable Style/ClassAndModuleChildren
module AssetHelper
# This monkey patch is needed to set the integrity attr to html tags for SRI.
# It was developed using information at the link above, along with lifting
# code out of the shakapacker gem, version 8.0.0, and modifying it.
module Shakapacker::Helper
def javascript_pack_tag(*names, defer: true, **options)
if @javascript_pack_tag_loaded
raise 'To prevent duplicated chunks on the page, you should call javascript_pack_tag only once on the page. ' \
'Please refer to https://github.com/shakacode/shakapacker/blob/main/README.md#view-helpers-javascript_pack_tag-and-stylesheet_pack_tag for the usage guide'
end
append_javascript_pack_tag(*names, defer: defer)
non_deferred = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:non_deferred], type: :javascript)
deferred = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:deferred], type: :javascript) - non_deferred
@javascript_pack_tag_loaded = true
capture do
render_javascript_tags(deferred, options, true)
concat "\n" if non_deferred.any? && deferred.any?
render_javascript_tags(non_deferred, options, false)
end
end
private def render_javascript_tags(sources, options, defer)
last_index = sources.size - 1
sources.each.with_index do |source, index|
tag_source = lookup_source(source)
tag_options = options.merge(defer: defer)
if include_subresource_integrity?
#:nocov:
integrity = lookup_integrity(source)
tag_options.merge!(integrity: integrity, crossorigin: 'anonymous') if integrity.present?
#:nocov:
end
concat javascript_include_tag(tag_source, **tag_options)
concat "\n" unless index == last_index
end
end
private def lookup_source(source)
(source.respond_to?(:dig) && source.dig('src')) || source # rubocop:disable Style/SingleArgumentDig
end
private def lookup_integrity(source)
(source.respond_to?(:dig) && source.dig('integrity')) || nil # rubocop:disable Style/SingleArgumentDig
end
# Only serve integrity metadata for HTTPS requests:
# http://www.w3.org/TR/SRI/#non-secure-contexts-remain-non-secure
private def include_subresource_integrity?
respond_to?(:request) && request && request.ssl?
end
end
end
# rubocop:enable Style/ClassAndModuleChildren
(Disclaimer: The view helper code above probably does not handle all scenarios. I wrote it to work with our Rails application and we still need to take it through our QA process. If anyone decides to use it, I highly suggest scrutinizing that code to make sure it is appropriate for your application.)
Desired behavior:
SRI support is a first-class feature in shakapacker, and easily enabled by doing something like this:
hey thanks for sharing this - I know vaguely of SRI but it's not something I've actively looked into, but I think if it's something we could make painless to do via Shakapacker (ideally to the point that it could just be on by default) I think that'd be a really awesome security win.
I'll try to get sometime this month to look over your code in more detail and what it might take to get it integrated in - please feel free to post any updates here, and I'll do the same about any learnings I have :)
@G-Rath Sounds good. I noticed that the Rails Sprockets gem has support for SRI, although its documentation states that the support is considered experimental at this point. It's an implementation to look at for ideas.
My company has asked me to implement subresource integrity security in our Rails application. We're using shakapacker/webpack for our JavaScript assets (Sprockets is handling the bundling of our stylesheets and images). After researching how to do this, I came to learn that SRI isn't a first class feature of Shakapacker, however there is some information out there that helped me to roll my own solution.
config/webpack/webpack.config.js
app/views/layouts/application.html.erb
app/helpers/asset_helper.rb
(Disclaimer: The view helper code above probably does not handle all scenarios. I wrote it to work with our Rails application and we still need to take it through our QA process. If anyone decides to use it, I highly suggest scrutinizing that code to make sure it is appropriate for your application.)
Desired behavior:
SRI support is a first-class feature in shakapacker, and easily enabled by doing something like this:
config/shakapacker.yml
view template
Actual behavior:
SRI support must be added through custom coding
Setup environment:
The text was updated successfully, but these errors were encountered: