defmodule Plug.CSRFProtection do @moduledoc """ Plug to protect from cross-site request forgery. For this plug to work, it expects a session to have been previously fetched. It will then compare the plug stored in the session with the one sent by the request to determine the validity of the request. For an invalid request the action taken is based on the `:with` option. The token may be sent by the request either via the params with key "_csrf_token" or a header with name "x-csrf-token". GET requests are not protected, as they should not have any side-effect or change your application state. JavaScript requests are an exception: by using a script tag, external websites can embed server-side generated JavaScript, which can leak information. For this reason, this plug also forbids any GET JavaScript request that is not XHR (or AJAX). ## Token generation This plug won't generate tokens automatically. Instead, tokens will be generated only when required by calling `Plug.CSRFProtection.get_csrf_token/0`. The token is then stored in the process dictionary to be set in the request. One may wonder: why the process dictionary? The CSRF token is usually generated inside forms which may be isolated from the connection. Storing them in the process dictionary allows them to be generated as a side-effect, becoming one of those rare situations where using the process dictionary is useful. ## Options * `:with` - should be one of `:exception` or `:clear_session`. Defaults to `:exception`. * `:exception` - for invalid requests, this plug will raise `Plug.CSRFProtection.InvalidCSRFTokenError`. * `:clear_session` - for invalid requests, this plug will set an empty session for only this request. Also any changes to the session during this request will be ignored. ## Disabling You may disable this plug by doing `Plug.Conn.put_private(:plug_skip_csrf_protection, true)`. This was made available for disabling `Plug.CSRFProtection` in tests and not for dynamically skipping `Plug.CSRFProtection` in production code. If you want specific routes to skip `Plug.CSRFProtection`, then use a different stack of plugs for that route that does not include `Plug.CSRFProtection`. ## Examples plug Plug.Session, ... plug :fetch_session plug Plug.CSRFProtection """ import Plug.Conn require Bitwise @unprotected_methods ~w(HEAD GET OPTIONS) defmodule InvalidCSRFTokenError do @moduledoc "Error raised when CSRF token is invalid." message = "invalid CSRF (Cross Site Forgery Protection) token, make sure all " <> "requests include a valid '_csrf_token' param or 'x-csrf-token' header" defexception message: message, plug_status: 403 end defmodule InvalidCrossOriginRequestError do @moduledoc "Error raised when non-XHR requests are used for Javascript responses." message = "security warning: an embedded