Skip to content

Commit

Permalink
Release v1.2.3
Browse files Browse the repository at this point in the history
  • Loading branch information
José Valim committed Feb 28, 2017
1 parent a08907b commit 9ae28a1
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 18 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Changelog

## v1.2.3

* Bug fixes
* [Plug.Crypto] Provide safer deserialization mechanisms
* [Plug.Static] Properly handle null bytes

## v1.2.2

* Bug fix
Expand Down
37 changes: 37 additions & 0 deletions lib/plug/crypto.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,43 @@ defmodule Plug.Crypto do

use Bitwise

@doc """
A restricted version a `:erlang.binary_to_term/1` that
forbids possibly unsafe terms.
"""
def safe_binary_to_term(binary) when is_binary(binary) do
safe_terms(:erlang.binary_to_term(binary))
end

defp safe_terms(list) when is_list(list) do
for item <- list, do: safe_terms(item)
list
end
defp safe_terms(tuple) when is_tuple(tuple) do
safe_tuple(tuple, tuple_size(tuple))
tuple
end
defp safe_terms(map) when is_map(map) do
for {key, value} <- map do
safe_terms(key)
safe_terms(value)
end
map
end
defp safe_terms(other) when is_atom(other) or is_number(other) or is_binary(other) or
is_pid(other) or is_reference(other) do
other
end
defp safe_terms(other) do
raise ArgumentError, "cannot deserialize #{inspect other}, the term is not safe for deserialization"
end

defp safe_tuple(_tuple, 0), do: :ok
defp safe_tuple(tuple, n) do
safe_terms(:erlang.element(n, tuple))
safe_tuple(tuple, n - 1)
end

@doc """
Masks the token on the left with the token on the right.
Expand Down
11 changes: 7 additions & 4 deletions lib/plug/session/cookie.ex
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,15 @@ defmodule Plug.Session.COOKIE do
binary
end

defp decode({:ok, binary}, :external_term_format, _log) do
defp decode({:ok, binary}, :external_term_format, log) do
{:term,
try do
:erlang.binary_to_term(binary)
Plug.Crypto.safe_binary_to_term(binary)
rescue
_ -> %{}
e ->
Logger.log log, "Plug.Session could not decode incoming session cookie. Reason: " <>
Exception.message(e)
%{}
end}
end

Expand All @@ -142,7 +145,7 @@ defmodule Plug.Session.COOKIE do
end

defp decode(:error, _serializer, log) do
Logger.log log, "Plug.Session could not decode incoming session cookie. " <>
Logger.log log, "Plug.Session could not verify incoming session cookie. " <>
"This may happen when the session settings change or a stale cookie is sent."
{nil, %{}}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/plug/static.ex
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,6 @@ defmodule Plug.Static do
do: []

defp invalid_path?([h|_]) when h in [".", "..", ""], do: true
defp invalid_path?([h|t]), do: String.contains?(h, ["/", "\\", ":"]) or invalid_path?(t)
defp invalid_path?([h|t]), do: String.contains?(h, ["/", "\\", ":", "\0"]) or invalid_path?(t)
defp invalid_path?([]), do: false
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Plug.Mixfile do
use Mix.Project

@version "1.2.2"
@version "1.2.3"

def project do
[app: :plug,
Expand Down
22 changes: 11 additions & 11 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
%{"cowboy": {:hex, :cowboy, "1.0.0", "d0b46a5e5f971c5543eb46f86fe76b9add567d12fb5262a852b8f27c64c0555d", [:make, :rebar], [{:cowlib, "~> 1.0.0", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, optional: false]}]},
"cowlib": {:hex, :cowlib, "1.0.0", "397d890d669e56d486b0b5329973ad1a07012412bc110d34a737698dd6941741", [:make], []},
"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], []},
"ex_doc": {:hex, :ex_doc, "0.13.2", "1059a588d2ad3ffab25a0b85c58abf08e437d3e7a9124ac255e1d15cec68ab79", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"hackney": {:hex, :hackney, "1.2.0", "41d352d5c272a150127517ab29e00cf5521a04af925f260667bf55161fbee68f", [:rebar], [{:idna, "~> 1.0.2", [hex: :idna, optional: false]}, {:ssl_verify_hostname, "~> 1.0.5", [hex: :ssl_verify_hostname, optional: false]}]},
"idna": {:hex, :idna, "1.0.2", "397e3d001c002319da75759b0a81156bf11849c71d565162436d50020cb7265e", [:make], []},
"inch_ex": {:hex, :inch_ex, "0.5.3", "39f11e96181ab7edc9c508a836b33b5d9a8ec0859f56886852db3d5708889ae7", [:mix], [{:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
%{"cowboy": {:hex, :cowboy, "1.0.0", "d0b46a5e5f971c5543eb46f86fe76b9add567d12fb5262a852b8f27c64c0555d", [], [{:cowlib, "~> 1.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "1.0.0", "397d890d669e56d486b0b5329973ad1a07012412bc110d34a737698dd6941741", [], [], "hexpm"},
"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.13.2", "1059a588d2ad3ffab25a0b85c58abf08e437d3e7a9124ac255e1d15cec68ab79", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.2.0", "41d352d5c272a150127517ab29e00cf5521a04af925f260667bf55161fbee68f", [:rebar], [{:idna, "~> 1.0.2", [hex: :idna, repo: "hexpm", optional: false]}, {:ssl_verify_hostname, "~> 1.0.5", [hex: :ssl_verify_hostname, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "1.0.2", "397e3d001c002319da75759b0a81156bf11849c71d565162436d50020cb7265e", [:make], [], "hexpm"},
"inch_ex": {:hex, :inch_ex, "0.5.3", "39f11e96181ab7edc9c508a836b33b5d9a8ec0859f56886852db3d5708889ae7", [:mix], [{:poison, "~> 1.5 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"json": {:hex, :json, "0.3.2", "e40a15993024a0cb4f5e22816d6be34002cc4463c61789ed35ec94c41911ebee", [:mix], []},
"mime": {:hex, :mime, "1.0.0", "b63027733bba00b1013bad14e25dc8b6629ecb817731544a88a0fd14f2a55685", [:mix], []},
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], []},
"ranch": {:hex, :ranch, "1.0.0", "e3ac054e4265de77e2d2696dd7e1d6a67b7525aade13ba10c860e7f499a0d433", [:make], []},
"ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5", "2e73e068cd6393526f9fa6d399353d7c9477d6886ba005f323b592d389fb47be", [:make], []}}
"mime": {:hex, :mime, "1.0.0", "b63027733bba00b1013bad14e25dc8b6629ecb817731544a88a0fd14f2a55685", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], [], "hexpm"},
"ranch": {:hex, :ranch, "1.0.0", "e3ac054e4265de77e2d2696dd7e1d6a67b7525aade13ba10c860e7f499a0d433", [], [], "hexpm"},
"ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5", "2e73e068cd6393526f9fa6d399353d7c9477d6886ba005f323b592d389fb47be", [:make], [], "hexpm"}}
11 changes: 10 additions & 1 deletion test/plug/crypto_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@ defmodule Plug.CryptoTest do
refute masked_compare(<<1>>, <<>>, <<0>>)
refute masked_compare(<<0>>, <<1>>, <<0>>)
end
end

test "safe_binary_to_term" do
value = %{1 => {:foo, ["bar", 2.0, self(), make_ref()]}}
assert safe_binary_to_term(:erlang.term_to_binary(value)) == value

assert_raise ArgumentError, fn ->
safe_binary_to_term(:erlang.term_to_binary(%{1 => {:foo, [fn -> :bar end]}}))
end
end
end
12 changes: 12 additions & 0 deletions test/plug/static_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ defmodule Plug.StaticTest do
conn(:get, "/public/c:\\foo.txt") |> call
end
assert Plug.Exception.status(exception) == 400

exception = assert_raise Plug.Static.InvalidPathError,
"invalid path for static asset", fn ->
call(conn(:get, "/public/sample.txt%00.html"))
end
assert Plug.Exception.status(exception) == 400

exception = assert_raise Plug.Static.InvalidPathError,
"invalid path for static asset", fn ->
call(conn(:get, "/public/sample.txt\0.html"))
end
assert Plug.Exception.status(exception) == 400
end

test "returns 400 for invalid paths" do
Expand Down

0 comments on commit 9ae28a1

Please sign in to comment.