{"id":17924995,"url":"https://github.com/mwpastore/rack-protection-maximum_cookie","last_synced_at":"2025-03-24T03:30:58.417Z","repository":{"id":56890191,"uuid":"108697635","full_name":"mwpastore/rack-protection-maximum_cookie","owner":"mwpastore","description":"Properly enforce cookie limits in Rack responses","archived":false,"fork":false,"pushed_at":"2023-02-23T17:12:18.000Z","size":28,"stargazers_count":11,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-19T02:38:15.957Z","etag":null,"topics":["cookies","rack","rack-middleware","ruby","rubygem"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mwpastore.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-29T01:56:23.000Z","updated_at":"2021-03-19T08:46:39.000Z","dependencies_parsed_at":"2022-08-21T00:50:23.576Z","dependency_job_id":null,"html_url":"https://github.com/mwpastore/rack-protection-maximum_cookie","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Frack-protection-maximum_cookie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Frack-protection-maximum_cookie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Frack-protection-maximum_cookie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwpastore%2Frack-protection-maximum_cookie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mwpastore","download_url":"https://codeload.github.com/mwpastore/rack-protection-maximum_cookie/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245204456,"owners_count":20577352,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cookies","rack","rack-middleware","ruby","rubygem"],"created_at":"2024-10-28T20:51:53.127Z","updated_at":"2025-03-24T03:30:58.120Z","avatar_url":"https://github.com/mwpastore.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rack::Protection::MaximumCookie\n\n[![Gem Version](https://badge.fury.io/rb/rack-protection-maximum_cookie.svg)](https://badge.fury.io/rb/rack-protection-maximum_cookie)\n[![Build Status](https://travis-ci.org/mwpastore/rack-protection-maximum_cookie.svg?branch=master)](https://travis-ci.org/mwpastore/rack-protection-maximum_cookie)\n\nSome bugs in Rack may cause cookies to be silently dropped\u0026mdash;or worse,\ntruncated, leading to token leakage (i.e. transmission of a private session\nover a insecure connection), cross-site scripting vulnerabilities, and/or\ncross-site request forgery vulnerabilities. This gem provides a middleware that\ntries to prevent these scenarios from occurring.\n\n### Caveats\n\n1.  Most modern browsers no longer have a [per-domain cookie size limit][1],\n    so if you only care about modern browsers, go ahead and set `:per_domain?`\n    to false. You'll benefit from the per-domain cookie limit and per-cookie\n    bytesize limit (since most browsers still have some form of these limits,\n    and Rack's built-in check for them is nonexistent in the former case and\n    not implemented correctly in the latter).\n\n2.  Browsers that do have per-domain cookie limits enforce these limits\n    client-side, cumulatively over time. If you were to set a new cookie, every\n    few minutes, one at a time, eventually you'd hit a limit. Or another\n    service could be setting cookies for the domain your service listens on. If\n    this is a concern for your app, see the `:stateful?` option below.\n\n    In practice, your service is most likely setting the same cookies, for the\n    same domains, every response, all in the same response, and it knows about\n    all the cookies being set, so the default behavior of this gem should be\n    appropriate in those cases.\n\n## Installation\n\nAdd this line to your app's Gemfile:\n\n```ruby\ngem 'rack-protection-maximum_cookie'\n```\n\nAnd then execute:\n\n```console\n$ bundle\n```\n\nOr install it yourself as:\n\n```console\n$ gem install rack-protection-maximum_cookie\n```\n\n## Usage\n\nAdd this statement to your Rackup script or middleware-capable Rack app such as\nSinatra:\n\n```ruby\nuse Rack::Protection::MaximumCookie\n```\n\nOr Rails:\n\n\u003e TODO: Somebody please tell me how to insert this and before or after what in\n\u003e Rails' middleware stack.\n\nThis middleware raises exceptions, so you'll want to use an error-reporting\nservice like Sentry, Rollbar, or Airbrake, and insert this middleware after it.\n\n### Advanced\n\nRack::Protection::MaximumCookie accepts the following `use`-time options:\n\n* `:limit` *Integer*\n\n  Maximum number of cookies per domain. **50 cookies by default.** Set to a\n  negative number to disable.\n\n* `:bytesize_limit` *Integer*\n\n  Maximum size\u0026mdash;in bytes\u0026mdash;of cookies per domain (if `:per_domain?` is\n  set to true), or the maximum size of each cookie (if `:per_domain?` is set to\n  false). **4,096 bytes by default.** Set to a negative number to disable.\n\n* `:overhead` *Integer*\n\n  Overhead\u0026mdash;in bytes\u0026mdash;per cookie. **Three (3) bytes by default.** Set to\n  zero to disable.\n\n* `:per_domain?` *Boolean*\n\n  If true, apply the bytesize limit (e.g. 4,096 bytes\u0026mdash;minus any\n  per-cookie overhead) per domain. **This is the default behavior.**\n\n  If false, apply the bytesize limit (e.g. 4,096 bytes\u0026mdash;minus any\n  overhead) per cookie.\n\n* `:strict?` *Boolean*\n\n  If false, each sub-domain gets its own quota, separate from its second-level\n  domain. **This is the default behavior.**\n\n  If true, `:per_domain?` is forced to true, and each second-level domain's\n  cookies count towards its sub-domains' quotas. For example, if you have\n  cookies for example\u003ci\u003e\u003c/i\u003e.org totaling 4,000 bytes, you wouldn't be able to\n  set an additional 100-byte cookie on foo.example\u003ci\u003e\u003c/i\u003e.org in the same\n  request.\n\n* `:stateful?` *Boolean*\n\n  If false, the cookies are evaluated for each response in isolation, i.e.\n  statelessly. **This is the default behavior.**\n\n  If true, `:strict?` is forced to true, and Rack::Protection::MaximumCookie\n  will attempt to compensate for cookies that were set for the domain in\n  previous responses (by this or other web services) but are not present in the\n  current response.\n\n  \u003e This mechanism has its limits. First of all, browsers don't send cookie\n  \u003e directives in request headers\u0026mdash;only key=value pairs\u0026mdash;so in order\n  \u003e to compute the actual size of these cookies,\n  \u003e Rack::Protection::MaximumCookie must estimate the upper bound of the\n  \u003e bytesize of the directives in the original Set-Cookie headers. This\n  \u003e *should* work reasonably well as long as your app doesn't rely on any\n  \u003e non-standard directives or other quirky browser behavior.\n  \u003e\n  \u003e Secondly, browsers won't send cookies if their paths don't match the\n  \u003e request path. This means that if you're setting two cookies, one for\n  \u003e example\u003ci\u003e\u003c/i\u003e.org/foo and one for example\u003ci\u003e\u003c/i\u003e.org/bar, requests to\n  \u003e either path won't include the other's cookie. That defeats this mechanism,\n  \u003e as both cookies count toward example\u003ci\u003e\u003c/i\u003e.org's quota, but they aren't\n  \u003e able to be properly accounted for in the request. The only \"workaround\" is\n  \u003e to architect your app such that all cookies are set under a path common to\n  \u003e all routes. Unfortunately, this may lead to other security issues.\n  \u003e\n  \u003e This is an ugly wart on HTTP and the reason why modern browsers don't have\n  \u003e per-domain cookie size limits and drop cookies instead of truncating them.\n\n#### Block Argument\n\nIf you don't want to raise exceptions, only want to raise exceptions under\ncertain conditions, or want to customize the exception, you can modify the\nbehavior by passing a block to the middleware initializer:\n\n```ruby\nuse Rack::Protection::MaximumCookie do |env|\n  raise MyCustomError, 'Someone broke the cookie jar!' if env['foo.bar']\nend\n```\n\nIf the block returns a truthy value, the default exception will be raised:\n\n```ruby\nuse(Rack::Protection::MaximumCookie) { |env| env['foo.bar'] }\n```\n\nKeep in mind that the block receives the mutated *response* `env`.\n\nI'm interested in hearing use-cases for this feature and I'm open to passing\nadditional arguments to the block. Open a new issue to document and discuss.\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run\n`rake spec` to run the tests. You can also run `bin/console` for an interactive\nprompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To\nrelease a new version, update the version number in `version.rb`, and then run\n`bundle exec rake release`, which will create a git tag for the version, push\ngit commits and tags, and push the `.gem` file to\n[rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at\nhttps://github.com/mwpastore/rack-protection-maximum_cookie.\n\nPlease let me know if I've made any invalid assumptions or conclusions about\nthe HTTP specification or older browser behavior.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT\nLicense](http://opensource.org/licenses/MIT).\n\n[1]: http://browsercookielimits.squawky.net\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwpastore%2Frack-protection-maximum_cookie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmwpastore%2Frack-protection-maximum_cookie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwpastore%2Frack-protection-maximum_cookie/lists"}