Submission Deadline:

The goals of this assignment are to:

  1. Implement a network service that provides password authentication
  2. Defend the service against denial-of-service attacks
  3. Defend the service against online password guessing attacks
  4. Defend the service against offline password guessing attacks (graduate only)

Service Specification

For this assignment, your service will implement a simple protocol using Protobuf v3 messages. In this protocol, each message is preceded by a two-byte, big-endian integer giving the length of the following message. The protocol is as shown below.

\[ \begin{align*} C \rightarrow S &: \mathsf{ExprRequest} \\ S \rightarrow C &: \mathsf{ExprResponse} \\ \end{align*} \]

The messages themselves are defined as follows.

syntax = "proto3";

// Client request
message ExprRequest {
    string username = 1;
    string password = 2;
    string expression = 3;

// Server response
message ExprResponse {
    bool authenticated = 1;
    string result = 2;

The protocol runs over TLS on port 46464/tcp.

Servers must implement user authentication by checking usernames and passwords against a provided database. The database will consist of a TOML document that contains an array of user objects with username and password_hash keys. Password hashes follow PHC string format. Use an appropriate library to support the following hash algorithms.

  • MD5
  • SHA-1
  • SHA-256
  • SHA-512
  • bcrypt
  • scrypt
  • Argon2

An example user database is as follows.

username = "mario"
password_hash = "$1$nYfBsUPE$tveMZDKeC3StsMe0LA/k.."

username = "luigi"
password_hash = "$5$rounds=535000$KXabkqjRS9WfMw2V$MEBaT9Hcbdvcg4f9s7LGCR.lUE2u8OeslxVlsaXZD29"

On successful authentication, the authenticated field must be set to true in the response. The server must also provide the result of evaluating the Python expression contained in the request’s expression field in the response’s result field. If authentication failed, authenticated must be set to false in the response and result is undefined.

Expression evaluation must be implemented by executing a Python interpreter on the expression. The result is the captured output of the evaluation (stdout only).

The service must be packaged as a container image that can be invoked with the following invocation. Note that the solution must take a serve command and a path to the user database as an argument.

$ podman run -it --rm \
    -p 46464:46464 \
    -v ${host_path}/users.toml:/tmp/users.toml \
    ${image_name} serve /tmp/users.toml

Defending Against Denial-of-Service Attacks

The service must implement defenses against several denial-of-service attacks.

  1. The server must not allow any one client to trivially block others. Thus, the server must provide concurrent service.

  2. The server must implement an application-level defense against flooding attacks. This defense should identify clients that send many invalid requests to the service, and block those IP addresses.

  3. The server must implement an application-level defense against “Slowloris”-style attacks, where attackers follow the protocol but do so slowly in order to tie up server resources. Thus, the server must time out slow clients.

  4. The server must defend against clients that consume server resources with long-running expression evaluations by identifying these evaluations, terminating them, and blocking the responsible users.

The strategies used to identify malicious clients are open design decisions. The server will be evaluated on its ability to block malicious clients (true positives) while preserving service to benign clients (avoiding false positives).

Defending Against Online Password Guessing

The service must identify and block clients that engage in online password guessing. The strategy used to do so is another open design decision. As above, the server will be evaluated in terms of its true and false positive rates.

Defending Against Offline Password Guessing

The service will be provided with a user database, and some users defined therein will have weak passwords. Your server must detect these accounts. This functionality must be invoked as follows, and write a filtered database to stdout.

$ podman run -it --rm \
    -v ${host_path}/users.toml:/tmp/users.toml \
    ${image_name} check_users /tmp/users.toml

The check_users command will be given 1 cpu/hour during evaluation, and will be scored on true/false positives.

Public Tests

A partial test suite is available, and can be invoked against your server as follows.

$ podman run -it --rm \ \
    ${server_address} ${server_port}

Submission Instructions

Package your solution as a gzipped TAR archive. Your solution should have the following basic structure.

$ tree -F 02-passwords
├── Containerfile
└── src/

The root directory must be named 02-passwords, and the source code to your solution should be contained in src/. Your Containerfile should produce an image that follows the invocation instructions above.

Submit the solution archive to Canvas.