Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CHANGELOG.md

## v0.47.0 (unreleased)
- The CRUD authentication example now accepts only local login and logout return paths, preventing crafted links from redirecting users to another site.
- **Mac users:** the downloadable `sqlpage-macos.tgz` now runs natively on Apple silicon (M-series Macs) and no longer runs on Intel Macs. Homebrew remains the recommended and easiest installation method. On an Intel Mac, [install Homebrew](https://brew.sh/) if needed, then run `brew install sqlpage` (or `brew update` followed by `brew upgrade sqlpage` if you already installed it with Homebrew). Open Terminal in your existing website folder and run `sqlpage` instead of `./sqlpage.bin`; keep your SQL files, database, and `sqlpage` configuration folder in place. Intel installations may build from source and take longer; see the [macOS installation guide](https://sql-page.com/your-first-sql-website/?os=macos#download) for setup and older macOS requirements.
- Updated sqlx-oldapi to v0.6.57 to fix SQL Server fallback expressions such as `ISNULL($missing, 'default')` truncating defaults or failing for date values when the bound variable is `NULL`.
- Fixed MSSQL `JSON_OBJECT('key': value)` expressions being rejected by SQLPage's parser, including when used in `SET` statements or nested in `sqlpage.*` function calls.
Expand Down
8 changes: 2 additions & 6 deletions examples/CRUD - Authentication/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,9 @@ SELECT
WHERE username = :username) AS password_hash;
```

If authentication succeeds, create_session.sql redirects back to starting page using the $path value as the final redirect target:
If authentication succeeds, create_session.sql redirects back to the starting page only when `$path` is a local URL path. It accepts paths beginning with one `/`, relative page names such as `currencies_list.sql`, and relative `./` or `../` paths. It rejects external URLs, authority-relative URLs (`//example.com`), backslashes, percent escapes, and control characters. An unsafe value falls back to `/` after login or `/login.sql` after logout. Keep this check when adapting the example to your own pages; add any extra return routes to your application's allowlist if you use one.

```sql
SELECT
'redirect' AS component,
ifnull($path, '/') AS link;
```
See [create_session.sql](www/create_session.sql) for the full local-path check. [logout.sql](www/logout.sql) applies the same check before redirecting.

### Adding User/Login/Logout buttons to the page menu

Expand Down
41 changes: 41 additions & 0 deletions examples/CRUD - Authentication/test.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,48 @@ HTTP 302
[Asserts]
header "Location" == "currencies_list.sql"

GET http://localhost:8080/logout.sql?path=.%2Fcurrencies_list.sql
HTTP 302
[Asserts]
header "Location" == "./currencies_list.sql"

GET http://localhost:8080/logout.sql?path=https%3A%2F%2Fevil.example
HTTP 302
[Asserts]
header "Location" == "/login.sql"

GET http://localhost:8080/logout.sql?path=%2F%2Fevil.example
HTTP 302
[Asserts]
header "Location" == "/login.sql"

GET http://localhost:8080/logout.sql?path=%2F%5Cevil.example
HTTP 302
[Asserts]
header "Location" == "/login.sql"

GET http://localhost:8080/logout.sql?path=%2F%252Fevil.example
HTTP 302
[Asserts]
header "Location" == "/login.sql"

GET http://localhost:8080/currencies_list.sql
HTTP 302
[Asserts]
header "Location" == "/login.sql?path=/currencies_list.sql"

POST http://localhost:8080/create_session.sql?path=https%3A%2F%2Fevil.example

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testing for create is not as robust as logout. we should test the same edge cases here

[FormParams]
username: admin
password: admin
HTTP 302
[Asserts]
header "Location" == "/"

POST http://localhost:8080/create_session.sql?path=.%2Fcurrencies_list.sql
[FormParams]
username: admin
password: admin
HTTP 302
[Asserts]
header "Location" == "./currencies_list.sql"
8 changes: 2 additions & 6 deletions examples/CRUD - Authentication/www/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,9 @@ SELECT
WHERE username = :username) AS password_hash;
```

If authentication succeeds, create_session.sql redirects back to starting page using the $path value as the final redirect target:
If authentication succeeds, create_session.sql redirects back to the starting page only when `$path` is a local URL path. It accepts paths beginning with one `/`, relative page names such as `currencies_list.sql`, and relative `./` or `../` paths. It rejects external URLs, authority-relative URLs (`//example.com`), backslashes, percent escapes, and control characters. An unsafe value falls back to `/` after login or `/login.sql` after logout. Keep this check when adapting the example to your own pages; add any extra return routes to your application's allowlist if you use one.

```sql
SELECT
'redirect' AS component,
ifnull($path, '/') AS link;
```
See [create_session.sql](create_session.sql) for the full local-path check. [logout.sql](logout.sql) applies the same check before redirecting.

### Adding User/Login/Logout buttons to the page menu

Expand Down
22 changes: 21 additions & 1 deletion examples/CRUD - Authentication/www/create_session.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ RETURNING
-- The user browser will now have a cookie named `session_token` that we can check later
-- to see if the user is logged in.

-- Only redirect to a local page. Relative links are accepted for existing
-- example pages such as currencies_list.sql.
SELECT
'redirect' AS component,
ifnull($path, '/') AS link;
iif(
$path IS NOT NULL
AND length($path) > 0
AND (
(substr($path, 1, 1) = '/' AND substr($path, 2, 1) <> '/')
OR (
(substr($path, 1, 1) GLOB '[A-Za-z0-9_]'
OR substr($path, 1, 2) = './'
OR substr($path, 1, 3) = '../')
AND instr($path, ':') = 0
)
)
AND instr($path, char(92)) = 0
AND instr($path, '%') = 0
AND instr($path, char(0)) = 0
AND ($path GLOB '*[' || char(1) || '-' || char(31) || char(127) || ']*') = 0,
$path,
'/'
) AS link;
Comment on lines +29 to +47

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this and the duplicated copy in logout would be cleaner to read as a CASE statement https://www.w3schools.com/sql/sql_case.asp something like

set return_to = CASE
    WHEN $path GLOB '*[' || char(1) || '-' || char(31) || char(127) || '%\]*' THEN NULL
    WHEN instr($path, char(0)) > 0                          THEN NULL
    WHEN $path = '/' OR $path GLOB '/[^/]*'                 THEN $path
    WHEN $path GLOB './*' OR $path GLOB '../*'              THEN $path
    WHEN $path GLOB '[A-Za-z0-9_]*' AND instr($path,':') = 0 THEN $path
END;

20 changes: 19 additions & 1 deletion examples/CRUD - Authentication/www/logout.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,22 @@ SELECT

SELECT
'redirect' AS component,
ifnull($path, '/login.sql') AS link -- redirect to the login page after the user logs out
iif(
$path IS NOT NULL
AND length($path) > 0
AND (
(substr($path, 1, 1) = '/' AND substr($path, 2, 1) <> '/')
OR (
(substr($path, 1, 1) GLOB '[A-Za-z0-9_]'
OR substr($path, 1, 2) = './'
OR substr($path, 1, 3) = '../')
AND instr($path, ':') = 0
)
)
AND instr($path, char(92)) = 0
AND instr($path, '%') = 0
AND instr($path, char(0)) = 0
AND ($path GLOB '*[' || char(1) || '-' || char(31) || char(127) || ']*') = 0,
$path,
'/login.sql'
) AS link; -- redirect to the login page after logout when the path is unsafe
Loading