From 3cfc7e21bab8cc4d6fb31265a1ee93fc426ccd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Thu, 19 Dec 2019 16:32:56 +0100 Subject: [PATCH] doc: Put examples into categories. Parameter injection example moved to security concerns instead (#101) --- docs/source/examples/examples.rst | 560 ------------------ .../examples/handling_http_requests.rst | 232 ++++++++ docs/source/examples/managing_routes.rst | 120 ++++ docs/source/examples/shell_tricks.rst | 26 + docs/source/examples/toc.rst | 6 +- docs/source/examples/using_json.rst | 69 +++ .../examples/working_with_pow_files.rst | 73 +++ docs/source/index.rst | 6 +- docs/source/the_project/security.rst | 54 +- 9 files changed, 582 insertions(+), 564 deletions(-) delete mode 100644 docs/source/examples/examples.rst create mode 100644 docs/source/examples/handling_http_requests.rst create mode 100644 docs/source/examples/managing_routes.rst create mode 100644 docs/source/examples/shell_tricks.rst create mode 100644 docs/source/examples/using_json.rst create mode 100644 docs/source/examples/working_with_pow_files.rst diff --git a/docs/source/examples/examples.rst b/docs/source/examples/examples.rst deleted file mode 100644 index 0d2187c..0000000 --- a/docs/source/examples/examples.rst +++ /dev/null @@ -1,560 +0,0 @@ -Using a pow File ----------------- - -A :file:`pow` file is just a :command:`bash` script, where you make calls to the -``kapow route`` command. - - -Starting *Kapow!* using a pow file -++++++++++++++++++++++++++++++++++ - -.. code-block:: console - :linenos: - - $ kapow server example.pow - -With the :file:`example.pow`: - -.. code-block:: console - :linenos: - - $ cat example.pow - # - # This is a simple example of a pow file - # - echo '[*] Starting my script' - - # We add 2 Kapow! routes - kapow route add /my/route -c 'echo hello world | kapow set /response/body' - kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body' - -.. note:: - - *Kapow!* can be fully configured using just :file:`pow` files - - -Load More Than One pow File ---------------------------- - -You can load more than one :file:`pow` file at time. This can help you keep -your :file:`pow` files tidy. - -.. code-block:: console - :linenos: - - $ ls pow-files/ - example-1.pow example-2.pow - $ kapow server <(cat pow-files/*.pow) - - -Add a New Route ---------------- - -.. warning:: - - Be aware that if you register more than one route with exactly the - same path, only the first route added will be used. - -GET route -+++++++++ - -Defining a route: - -.. code-block:: console - :linenos: - - $ kapow route add /my/route -c 'echo hello world | kapow set /response/body' - - -Calling route: - -.. code-block:: console - :linenos: - - $ curl http://localhost:8080/my/route - hello world - -POST route -++++++++++ - -Defining a route: - -.. code-block:: console - :linenos: - - $ kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body' - - -Calling a route: - -.. code-block:: console - :linenos: - - $ curl -d 'hello world' -X POST http://localhost:8080/echo - hello world - - -Adding URL params -+++++++++++++++++ - -Defining a route: - -.. code-block:: console - :linenos: - - $ kapow route add '/echo/{message}' -c 'kapow get /request/matches/message | kapow set /response/body' - - -Calling a route: - -.. code-block:: console - :linenos: - - $ curl http://localhost:8080/echo/hello%20world - hello world - - -Listing Routes --------------- - -You can list the active routes in the *Kapow!* server. - -.. _listing-routes-example: - -.. code-block:: console - :linenos: - - $ kapow route list - [{"id":"20c98328-0b82-11ea-90a8-784f434dfbe2","method":"GET","url_pattern":"/echo/{message}","entrypoint":"/bin/sh -c","command":"kapow get /request/matches/message | kapow set /response/body"}] - -Or, if you want human-readable output, you can use :program:`jq`: - -.. code-block:: console - :linenos: - - $ kapow route list | jq - [ - { - "id": "20c98328-0b82-11ea-90a8-784f434dfbe2", - "method": "GET", - "url_pattern": "/echo/{message}", - "entrypoint": "/bin/sh -c", - "command": "kapow get /request/matches/message | kapow set /response/body", - } - ] - - -.. note:: - - *Kapow!* has a :ref:`http-control-interface`, bound by default to - ``localhost:8081``. - - -Deleting Routes ---------------- - -You need the ID of a route to delete it. -Running the command used in the :ref:`listing routes example -`, you can obtain the ID of the route, and then delete -it by typing: - -.. code-block:: console - :linenos: - - $ kapow route remove 20c98328-0b82-11ea-90a8-784f434dfbe2 - - -Writing Multiline pow Files ---------------------------- - -If you need to write more complex actions, you can leverage multiline commands: - -.. code-block:: console - :linenos: - - $ cat multiline.pow - kapow route add /log_and_stuff - <<-'EOF' - echo this is a quite long sentence and other stuff | tee log.txt | kapow set /response/body - cat log.txt | kapow set /response/body - EOF - -.. warning:: - - Be aware of the **"-"** at the end of the ``kapow route add`` command. - It tells ``kapow route add`` to read commands from `stdin`. - -.. warning:: - - If you want to learn more about multiline usage, see: `Here Doc - `_ - - -Add or Modify an HTTP Header ----------------------------- - -You may want to add some extra HTTP header to the response. - -In this example we'll be adding the header ``X-Content-Type-Options`` to the response. - -.. code-block:: console - :linenos: - - $ cat sniff.pow - kapow route add /sec-hello-world - <<-'EOF' - kapow set /response/headers/X-Content-Type-Options nosniff - kapow set /response/headers/Content-Type text/plain - - echo this will be interpreted as plain text | kapow set /response/body - EOF - - $ kapow server nosniff.pow - -Testing with :program:`curl`: - -.. code-block:: console - :emphasize-lines: 11 - :linenos: - - $ curl -v http://localhost:8080/sec-hello-world - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /sec-hello-word HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 200 OK - < X-Content-Type-Options: nosniff - < Date: Wed, 20 Nov 2019 10:56:46 GMT - < Content-Length: 24 - < Content-Type: text/plain - < - this will be interpreted as plain text - -.. warning:: - - Please be aware that if you don't explicitly specify the value of - the ``Content-Type`` header, *Kapow!* will guess it, effectively - negating the effect of the ``X-Content-Type-Options`` header. - -.. note:: - - You can read more about the ``X-Content-Type-Options: nosniff`` header `here - `_. - - -Modify JSON by Using Shell Commands ------------------------------------ - -.. note:: - - Nowadays Web services are `JSON`-based, so making your script `JSON` aware is - probably a good choice. In order to be able to extract data from a `JSON` - document as well as composing `JSON` documents from a script, you can leverage - `jq `_. - - -Example #1 -++++++++++ - -In this example our *Kapow!* service will receive a `JSON` value with an incorrect -date, then our ``pow`` file will fix it and return the correct value to the user. - -.. code-block:: console - :linenos: - - $ cat fix_date.pow - kapow route add -X POST /fix-date - <<-'EOF' - kapow set /response/headers/Content-Type application/json - kapow get /request/body | jq --arg newdate "$(date +'%Y-%m-%d_%H-%M-%S')" '.incorrectDate=$newdate' | kapow set /response/body - EOF - -Call the service with :program:`curl`: - -.. code-block:: console - :linenos: - - $ curl -X POST http://localhost:8080/fix-date -H 'Content-Type: application/json' -d '{"incorrectDate": "no way, Jose"}' - { - "incorrectDate": "2019-11-22_10-42-06" - } - - -Example #2 -++++++++++ - -In this example we extract the ``name`` field from the incoming `JSON` document in -order to generate a two-attribute `JSON` response. - -.. code-block:: console - - $ cat echo-attribute.pow - kapow route add -X POST /echo-attribute - <<-'EOF' - JSON_WHO=$(kapow get /request/body | jq -r .name) - - kapow set /response/headers/Content-Type application/json - kapow set /response/status 200 - - jq --arg greet Hello --arg value "${JSON_WHO:-World}" --null-input '{ greet: $greet, to: $value }' | kapow set /response/body - EOF - -Call the service with :program:`curl`: - -.. code-block:: console - :linenos: - :emphasize-lines: 4 - - $ curl -X POST http://localhost:8080/echo-attribute -H 'Content-Type: application/json' -d '{"name": "MyName"}' - { - "greet": "Hello", - "to": "MyName" - } - - -Upload Files ------------- - -Example #1 -++++++++++ - -Uploading a file using *Kapow!* is very simple: - -.. code-block:: console - :linenos: - - $ cat upload.pow - kapow route add -X POST /upload-file - <<-'EOF' - kapow get /request/files/data/content | kapow set /response/body - EOF - -.. code-block:: console - :linenos: - - $ cat results.json - {"hello": "world"} - $ curl -X POST -H 'Content-Type: multipart/form-data' -F data=@results.json http://localhost:8080/upload-file - {"hello": "world"} - - -Example #2 -++++++++++ - -In this example we reply the line count of the file received in the request: - -.. code-block:: console - :linenos: - - $ cat count-file-lines.pow - kapow route add -X POST /count-file-lines - <<-'EOF' - - # Get sent file - FNAME=$(kapow get /request/files/myfile/filename) - - # Counting file lines - LCOUNT=$(kapow get /request/files/myfile/content | wc -l) - - kapow set /response/status 200 - - echo "$FNAME has $LCOUNT lines" | kapow set /response/body - EOF - -.. code-block:: console - :linenos: - - $ cat file.txt - hello - World - $ curl -F myfile=@file.txt http://localhost:8080/count-file-lines - file.txt has 2 lines - - -Protecting Against Parameter Injection Attacks ----------------------------------------------- - -When you resolve variable values be careful to tokenize correctly by using -double quotes. Otherwise you could be vulnerable to **parameter injection -attacks**. - -**This example is VULNERABLE to parameter injection** - -In this example, an attacker can inject arbitrary parameters to :command:`ls`. - -.. code-block:: console - :linenos: - - $ cat command-injection.pow - kapow route add '/vulnerable/{value}' - <<-'EOF' - ls $(kapow get /request/matches/value) | kapow set /response/body - EOF - -Exploiting using :program:`curl`: - -.. code-block:: console - :linenos: - - $ curl http://localhost:8080/vulnerable/-lai%20hello - -**This example is NOT VULNERABLE to parameter injection** - -Note how we add double quotes when we recover *value* data from the -request: - -.. code-block:: console - :linenos: - - $ cat command-injection.pow - kapow route add '/not-vulnerable/{value}' - <<-'EOF' - ls -- "$(kapow get /request/matches/value)" | kapow set /response/body - EOF - - -.. warning:: - - Quotes around parameters only protect against the injection of additional - arguments, but not against turning a non-option into option or vice-versa. - Note that for many commands we can leverage double-dash to signal the end of - the options. See the "Security Concern" section on the docs. - - -Sending HTTP error codes ------------------------- - -You can specify custom status code for `HTTP` response: - -.. code-block:: console - :linenos: - - $ cat error.pow - kapow route add /error - <<-'EOF' - kapow set /response/status 401 - echo -n '401 error' | kapow set /response/body - EOF - -Testing with :program:`curl`: - -.. code-block:: console - :emphasize-lines: 10 - :linenos: - - $ curl -v http://localhost:8080/error - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /error HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 401 Unauthorized - < Date: Wed, 20 Nov 2019 14:06:44 GMT - < Content-Length: 10 - < Content-Type: text/plain; charset=utf-8 - < - 401 error - - -How to redirect using HTTP --------------------------- - -In this example we'll redirect our users to `Google`: - -.. code-block:: console - :linenos: - - $ cat redirect.pow - kapow route add /redirect - <<-'EOF' - kapow set /response/headers/Location https://google.com - kapow set /response/status 301 - EOF - -.. code-block:: console - :emphasize-lines: 10-11 - :linenos: - - $ curl -v http://localhost:8080/redirect - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /redirect HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 301 Moved Permanently - < Location: http://google.com - < Date: Wed, 20 Nov 2019 11:39:24 GMT - < Content-Length: 0 - < - * Connection #0 to host localhost left intact - - -How to Execute Two Processes in Parallel ----------------------------------------- - -We want to :command:`ping` two machines parallel. *Kapow!* can get IP addresses -from query params: - -.. code-block:: console - :linenos: - - $ cat parallel.pow - kapow route add '/parallel/{ip1}/{ip2}' - <<-'EOF' - ping -c 1 -- "$(kapow get /request/matches/ip1)" | kapow set /response/body & - ping -c 1 -- "$(kapow get /request/matches/ip2)" | kapow set /response/body & - wait - EOF - -Calling with :program:`curl`: - -.. code-block:: console - :linenos: - - $ curl -v http://localhost:8080/parallel/10.0.0.1/10.10.10.1 - - -Manage Cookies --------------- - -If you track down some user state, *Kapow!* allows you manage Request/Response -Cookies. - -In the next example we'll set a cookie: - -.. code-block:: console - :linenos: - - $ cat cookie.pow - kapow route add /setcookie - <<-'EOF' - CURRENT_STATUS=$(kapow get /request/cookies/kapow-status) - - if [ -z "$CURRENT_STATUS" ]; then - kapow set /response/cookies/Kapow-Status 'Kapow Cookie Set' - fi - - echo -n OK | kapow set /response/body - EOF - -Calling with :program:`curl`: - -.. code-block:: console - :linenos: - :emphasize-lines: 11 - - $ curl -v http://localhost:8080/setcookie - * Trying ::1... - * TCP_NODELAY set - * Connected to localhost (::1) port 8080 (#0) - > GET /setcookie HTTP/1.1 - > Host: localhost:8080 - > User-Agent: curl/7.54.0 - > Accept: */* - > - < HTTP/1.1 200 OK - < Set-Cookie: Kapow-Status="Kapow Cookie Set" - < Date: Fri, 22 Nov 2019 10:44:42 GMT - < Content-Length: 3 - < Content-Type: text/plain; charset=utf-8 - < - OK - * Connection #0 to host localhost left intact diff --git a/docs/source/examples/handling_http_requests.rst b/docs/source/examples/handling_http_requests.rst new file mode 100644 index 0000000..246001e --- /dev/null +++ b/docs/source/examples/handling_http_requests.rst @@ -0,0 +1,232 @@ +Handling HTTP Requests +====================== + +Add or Modify an HTTP Header +---------------------------- + +You may want to add some extra HTTP header to the response. + +In this example we'll be adding the header ``X-Content-Type-Options`` to the response. + +.. code-block:: console + :linenos: + + $ cat sniff.pow + kapow route add /sec-hello-world - <<-'EOF' + kapow set /response/headers/X-Content-Type-Options nosniff + kapow set /response/headers/Content-Type text/plain + + echo this will be interpreted as plain text | kapow set /response/body + EOF + + $ kapow server nosniff.pow + +Testing with :program:`curl`: + +.. code-block:: console + :emphasize-lines: 11 + :linenos: + + $ curl -v http://localhost:8080/sec-hello-world + * Trying ::1... + * TCP_NODELAY set + * Connected to localhost (::1) port 8080 (#0) + > GET /sec-hello-word HTTP/1.1 + > Host: localhost:8080 + > User-Agent: curl/7.54.0 + > Accept: */* + > + < HTTP/1.1 200 OK + < X-Content-Type-Options: nosniff + < Date: Wed, 20 Nov 2019 10:56:46 GMT + < Content-Length: 24 + < Content-Type: text/plain + < + this will be interpreted as plain text + +.. warning:: + + Please be aware that if you don't explicitly specify the value of + the ``Content-Type`` header, *Kapow!* will guess it, effectively + negating the effect of the ``X-Content-Type-Options`` header. + +.. note:: + + You can read more about the ``X-Content-Type-Options: nosniff`` header `here + `_. + + +Upload Files +------------ + +Example #1 +++++++++++ + +Uploading a file using *Kapow!* is very simple: + +.. code-block:: console + :linenos: + + $ cat upload.pow + kapow route add -X POST /upload-file - <<-'EOF' + kapow get /request/files/data/content | kapow set /response/body + EOF + +.. code-block:: console + :linenos: + + $ cat results.json + {"hello": "world"} + $ curl -X POST -H 'Content-Type: multipart/form-data' -F data=@results.json http://localhost:8080/upload-file + {"hello": "world"} + + +Example #2 +++++++++++ + +In this example we reply the line count of the file received in the request: + +.. code-block:: console + :linenos: + + $ cat count-file-lines.pow + kapow route add -X POST /count-file-lines - <<-'EOF' + + # Get sent file + FNAME=$(kapow get /request/files/myfile/filename) + + # Counting file lines + LCOUNT=$(kapow get /request/files/myfile/content | wc -l) + + kapow set /response/status 200 + + echo "$FNAME has $LCOUNT lines" | kapow set /response/body + EOF + +.. code-block:: console + :linenos: + + $ cat file.txt + hello + World + $ curl -F myfile=@file.txt http://localhost:8080/count-file-lines + file.txt has 2 lines + + +Sending HTTP error codes +------------------------ + +You can specify custom status code for `HTTP` response: + +.. code-block:: console + :linenos: + + $ cat error.pow + kapow route add /error - <<-'EOF' + kapow set /response/status 401 + echo -n '401 error' | kapow set /response/body + EOF + +Testing with :program:`curl`: + +.. code-block:: console + :emphasize-lines: 10 + :linenos: + + $ curl -v http://localhost:8080/error + * Trying ::1... + * TCP_NODELAY set + * Connected to localhost (::1) port 8080 (#0) + > GET /error HTTP/1.1 + > Host: localhost:8080 + > User-Agent: curl/7.54.0 + > Accept: */* + > + < HTTP/1.1 401 Unauthorized + < Date: Wed, 20 Nov 2019 14:06:44 GMT + < Content-Length: 10 + < Content-Type: text/plain; charset=utf-8 + < + 401 error + + +How to redirect using HTTP +-------------------------- + +In this example we'll redirect our users to `Google`: + +.. code-block:: console + :linenos: + + $ cat redirect.pow + kapow route add /redirect - <<-'EOF' + kapow set /response/headers/Location https://google.com + kapow set /response/status 301 + EOF + +.. code-block:: console + :emphasize-lines: 10-11 + :linenos: + + $ curl -v http://localhost:8080/redirect + * Trying ::1... + * TCP_NODELAY set + * Connected to localhost (::1) port 8080 (#0) + > GET /redirect HTTP/1.1 + > Host: localhost:8080 + > User-Agent: curl/7.54.0 + > Accept: */* + > + < HTTP/1.1 301 Moved Permanently + < Location: http://google.com + < Date: Wed, 20 Nov 2019 11:39:24 GMT + < Content-Length: 0 + < + * Connection #0 to host localhost left intact + + +Manage Cookies +-------------- + +If you track down some user state, *Kapow!* allows you manage Request/Response +Cookies. + +In the next example we'll set a cookie: + +.. code-block:: console + :linenos: + + $ cat cookie.pow + kapow route add /setcookie - <<-'EOF' + CURRENT_STATUS=$(kapow get /request/cookies/kapow-status) + + if [ -z "$CURRENT_STATUS" ]; then + kapow set /response/cookies/Kapow-Status 'Kapow Cookie Set' + fi + + echo -n OK | kapow set /response/body + EOF + +Calling with :program:`curl`: + +.. code-block:: console + :linenos: + :emphasize-lines: 11 + + $ curl -v http://localhost:8080/setcookie + * Trying ::1... + * TCP_NODELAY set + * Connected to localhost (::1) port 8080 (#0) + > GET /setcookie HTTP/1.1 + > Host: localhost:8080 + > User-Agent: curl/7.54.0 + > Accept: */* + > + < HTTP/1.1 200 OK + < Set-Cookie: Kapow-Status="Kapow Cookie Set" + < Date: Fri, 22 Nov 2019 10:44:42 GMT + < Content-Length: 3 + < Content-Type: text/plain; charset=utf-8 + < + OK + * Connection #0 to host localhost left intact diff --git a/docs/source/examples/managing_routes.rst b/docs/source/examples/managing_routes.rst new file mode 100644 index 0000000..299273c --- /dev/null +++ b/docs/source/examples/managing_routes.rst @@ -0,0 +1,120 @@ +Managing Routes +=============== + +Adding New Routes +----------------- + +.. warning:: + + Be aware that if you register more than one route with exactly the + same path, only the first route added will be used. + +GET route ++++++++++ + +Defining a route: + +.. code-block:: console + :linenos: + + $ kapow route add /my/route -c 'echo hello world | kapow set /response/body' + + +Calling route: + +.. code-block:: console + :linenos: + + $ curl http://localhost:8080/my/route + hello world + +POST route +++++++++++ + +Defining a route: + +.. code-block:: console + :linenos: + + $ kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body' + + +Calling a route: + +.. code-block:: console + :linenos: + + $ curl -d 'hello world' -X POST http://localhost:8080/echo + hello world + + +Capturing Parts of the URL +++++++++++++++++++++++++++ + +Defining a route: + +.. code-block:: console + :linenos: + + $ kapow route add '/echo/{message}' -c 'kapow get /request/matches/message | kapow set /response/body' + + +Calling a route: + +.. code-block:: console + :linenos: + + $ curl http://localhost:8080/echo/hello%20world + hello world + + +Listing Routes +-------------- + +You can list the active routes in the *Kapow!* server. + +.. _listing-routes-example: + +.. code-block:: console + :linenos: + + $ kapow route list + [{"id":"20c98328-0b82-11ea-90a8-784f434dfbe2","method":"GET","url_pattern":"/echo/{message}","entrypoint":"/bin/sh -c","command":"kapow get /request/matches/message | kapow set /response/body"}] + +Or, if you want human-readable output, you can use :program:`jq`: + +.. code-block:: console + :linenos: + + $ kapow route list | jq + [ + { + "id": "20c98328-0b82-11ea-90a8-784f434dfbe2", + "method": "GET", + "url_pattern": "/echo/{message}", + "entrypoint": "/bin/sh -c", + "command": "kapow get /request/matches/message | kapow set /response/body", + } + ] + + +.. note:: + + *Kapow!* has a :ref:`http-control-interface`, bound by default to + ``localhost:8081``. + + +Deleting Routes +--------------- + +You need the ID of a route to delete it. +Running the command used in the :ref:`listing routes example +`, you can obtain the ID of the route, and then delete +it by typing: + +.. code-block:: console + :linenos: + + $ kapow route remove 20c98328-0b82-11ea-90a8-784f434dfbe2 + + diff --git a/docs/source/examples/shell_tricks.rst b/docs/source/examples/shell_tricks.rst new file mode 100644 index 0000000..5ba7720 --- /dev/null +++ b/docs/source/examples/shell_tricks.rst @@ -0,0 +1,26 @@ +Shell Tricks +============ + +How to Execute Two Processes in Parallel +---------------------------------------- + +We want to :command:`ping` two machines parallel. *Kapow!* can get IP addresses +from query params: + +.. code-block:: console + :linenos: + + $ cat parallel.pow + kapow route add '/parallel/{ip1}/{ip2}' - <<-'EOF' + ping -c 1 -- "$(kapow get /request/matches/ip1)" | kapow set /response/body & + ping -c 1 -- "$(kapow get /request/matches/ip2)" | kapow set /response/body & + wait + EOF + +Calling with :program:`curl`: + +.. code-block:: console + :linenos: + + $ curl -v http://localhost:8080/parallel/10.0.0.1/10.10.10.1 + diff --git a/docs/source/examples/toc.rst b/docs/source/examples/toc.rst index 29ebca9..8ac3108 100644 --- a/docs/source/examples/toc.rst +++ b/docs/source/examples/toc.rst @@ -3,4 +3,8 @@ Examples .. toctree:: - examples + working_with_pow_files + managing_routes + handling_http_requests + using_json + shell_tricks diff --git a/docs/source/examples/using_json.rst b/docs/source/examples/using_json.rst new file mode 100644 index 0000000..4c5dbb5 --- /dev/null +++ b/docs/source/examples/using_json.rst @@ -0,0 +1,69 @@ +Using JSON +========== + +Modify JSON by Using Shell Commands +----------------------------------- + +.. note:: + + Nowadays Web services are `JSON`-based, so making your script `JSON` aware is + probably a good choice. In order to be able to extract data from a `JSON` + document as well as composing `JSON` documents from a script, you can leverage + `jq `_. + + +Example #1 +++++++++++ + +In this example our *Kapow!* service will receive a `JSON` value with an incorrect +date, then our ``pow`` file will fix it and return the correct value to the user. + +.. code-block:: console + :linenos: + + $ cat fix_date.pow + kapow route add -X POST /fix-date - <<-'EOF' + kapow set /response/headers/Content-Type application/json + kapow get /request/body | jq --arg newdate "$(date +'%Y-%m-%d_%H-%M-%S')" '.incorrectDate=$newdate' | kapow set /response/body + EOF + +Call the service with :program:`curl`: + +.. code-block:: console + :linenos: + + $ curl -X POST http://localhost:8080/fix-date -H 'Content-Type: application/json' -d '{"incorrectDate": "no way, Jose"}' + { + "incorrectDate": "2019-11-22_10-42-06" + } + + +Example #2 +++++++++++ + +In this example we extract the ``name`` field from the incoming `JSON` document in +order to generate a two-attribute `JSON` response. + +.. code-block:: console + + $ cat echo-attribute.pow + kapow route add -X POST /echo-attribute - <<-'EOF' + JSON_WHO=$(kapow get /request/body | jq -r .name) + + kapow set /response/headers/Content-Type application/json + kapow set /response/status 200 + + jq --arg greet Hello --arg value "${JSON_WHO:-World}" --null-input '{ greet: $greet, to: $value }' | kapow set /response/body + EOF + +Call the service with :program:`curl`: + +.. code-block:: console + :linenos: + :emphasize-lines: 4 + + $ curl -X POST http://localhost:8080/echo-attribute -H 'Content-Type: application/json' -d '{"name": "MyName"}' + { + "greet": "Hello", + "to": "MyName" + } diff --git a/docs/source/examples/working_with_pow_files.rst b/docs/source/examples/working_with_pow_files.rst new file mode 100644 index 0000000..610cdd2 --- /dev/null +++ b/docs/source/examples/working_with_pow_files.rst @@ -0,0 +1,73 @@ +Working with pow Files +====================== + +Starting *Kapow!* using a pow file +---------------------------------- + +A :file:`pow` file is just a :command:`bash` script, where you make calls to the +``kapow route`` command. + +.. code-block:: console + :linenos: + + $ kapow server example.pow + +With the :file:`example.pow`: + +.. code-block:: console + :linenos: + + $ cat example.pow + # + # This is a simple example of a pow file + # + echo '[*] Starting my script' + + # We add 2 Kapow! routes + kapow route add /my/route -c 'echo hello world | kapow set /response/body' + kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body' + +.. note:: + + *Kapow!* can be fully configured using just :file:`pow` files + + +Load More Than One pow File +--------------------------- + +You can load more than one :file:`pow` file at time. This can help you keep +your :file:`pow` files tidy. + +.. code-block:: console + :linenos: + + $ ls pow-files/ + example-1.pow example-2.pow + $ kapow server <(cat pow-files/*.pow) + + +Writing Multiline pow Files +--------------------------- + +If you need to write more complex actions, you can leverage multiline commands: + +.. code-block:: console + :linenos: + + $ cat multiline.pow + kapow route add /log_and_stuff - <<-'EOF' + echo this is a quite long sentence and other stuff | tee log.txt | kapow set /response/body + cat log.txt | kapow set /response/body + EOF + +.. warning:: + + Be aware of the **"-"** at the end of the ``kapow route add`` command. + It tells ``kapow route add`` to read commands from `stdin`. + +.. warning:: + + If you want to learn more about multiline usage, see: `Here Doc + `_ + + diff --git a/docs/source/index.rst b/docs/source/index.rst index a0f25e8..0670403 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -74,7 +74,11 @@ Contents :maxdepth: 2 :caption: Usage Examples - examples/examples + examples/working_with_pow_files + examples/managing_routes + examples/handling_http_requests + examples/using_json + examples/shell_tricks .. toctree:: :maxdepth: 2 diff --git a/docs/source/the_project/security.rst b/docs/source/the_project/security.rst index 3de3159..1253d5b 100644 --- a/docs/source/the_project/security.rst +++ b/docs/source/the_project/security.rst @@ -14,8 +14,56 @@ as well as the way the command itself interprets them, in order to get it right. going feed it as a parameter to a command line program. -Example of Unsafe Parameter Handling ------------------------------------- +Parameter Injection Attacks +--------------------------- + +When you resolve variable values be careful to tokenize correctly by using +double quotes. Otherwise you could be vulnerable to **parameter injection +attacks**. + +**This example is VULNERABLE to parameter injection** + +In this example, an attacker can inject arbitrary parameters to :command:`ls`. + +.. code-block:: console + :linenos: + + $ cat command-injection.pow + kapow route add '/vulnerable/{value}' - <<-'EOF' + ls $(kapow get /request/matches/value) | kapow set /response/body + EOF + +Exploiting using :program:`curl`: + +.. code-block:: console + :linenos: + + $ curl http://localhost:8080/vulnerable/-lai%20hello + +**This example is NOT VULNERABLE to parameter injection** + +Note how we add double quotes when we recover *value* data from the +request: + +.. code-block:: console + :linenos: + + $ cat command-injection.pow + kapow route add '/not-vulnerable/{value}' - <<-'EOF' + ls -- "$(kapow get /request/matches/value)" | kapow set /response/body + EOF + + +.. warning:: + + Quotes around parameters only protect against the injection of additional + arguments, but not against turning a non-option into option or vice-versa. + Note that for many commands we can leverage double-dash to signal the end of + the options. See the "Security Concern" section on the docs. + + +Parameter Mangling Attacks +-------------------------- Let's consider the following route: @@ -83,3 +131,5 @@ Let's see how we can handle this particular case: Since this is critical for keeping your *Kapow!* services secure, we are working on a way to make this more transparent and safe, while at the same time keeping it *Kapowy*. + +