Skip to content

Commit 005180d

Browse files
committed
new function: sqlpage.protocol
1 parent 3bc76da commit 005180d

File tree

8 files changed

+97
-29
lines changed

8 files changed

+97
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Fix bad contrast in links in custom page footers.
1515
- Add a new [configuration option](./configuration.md): `environment`. This allows you to set the environment in which SQLPage is running. It can be either `development` or `production`. In `production` mode, SQLPage will hide error messages and stack traces from the user, and will cache sql files in memory to avoid reloading them from disk when under heavy load.
1616
- Add support for `selected` in multi-select inputs in the [form](https://sql.ophir.dev/documentation.sql?component=form#component) component. This allows you to pre-select some options in a multi-select input.
17+
- New function: [`sqlpage.protocol`](https://sql.ophir.dev/functions.sql?function=protocol#function) to get the protocol used to access the current page. This is useful to build links that point to your own site, and work both in http and https.
1718

1819
## 0.17.0
1920

Cargo.lock

Lines changed: 26 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/official-site/safety.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@ However, if you implement your own session management system using the [`cookie`
103103
you should be careful to follow the [OWASP session management best practices](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#cookies).
104104
Implementing your own session management system is not recommended if you are a non-technical user and don''t have a good understanding of web security.
105105
106+
## Protection against [CSRF attacks](https://en.wikipedia.org/wiki/Cross-site_request_forgery)
107+
108+
The recommended way to store session tokens for user authentication
109+
in SQLPage is to use the [`cookie` component](/documentation.sql?component=cookie#component).
110+
111+
All cookies set by SQLPage have the `SameSite` attribute set to `strict` by default,
112+
which means that they will only be sent to your website if the user is already on your website.
113+
An attacker cannot make a user''s browser send a request to your website from another (malicious)
114+
website, and have it perform an action on your website in the user''s name,
115+
because the browser will not send the cookies to your website.
116+
117+
SQLPage differentiates between POST variables (accessed with the `:variable` syntax), and
118+
variables that can come from URL parameters (accessible with `$variable`).
119+
120+
When a user submits a form, you should use POST variables to access the form data.
121+
This ensures that you only use data that indeed comes from the form, and not from a
122+
URL parameter that could be part of a malicious link.
123+
124+
Advanced users who may want to implement their own csrf protection system can do so
125+
using the [`sqlpage.random_string()`](/functions.sql?function=random_string#function) function,
126+
and the `hidden` input type of the [`form`](/documentation.sql?component=form#component) component.
127+
128+
For more information, see the [this discussion](https://github.com/lovasoa/SQLpage/discussions/148).
129+
106130
## Database connections
107131
108132
SQLPage uses a fixed pool of database connections, and will never open more connections than the ones you

examples/official-site/sqlpage/migrations/01_documentation.sql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,11 @@ or to implement more complex flows, such as a multi-step form,
365365
where the user is redirected to a different page after each step.
366366
367367
This can also be used to implement [CSRF protection](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern),
368-
if your website has authenticated users that can perform sensitive actions through forms.
368+
if your website has authenticated users that can perform sensitive actions through simple links.
369+
But note that SQLPage cookies already have the `SameSite=strict` attribute by default, which protects you against CSRF attacks by default in most cases.
370+
369371
', json('[{"component":"form", "validate": "Delete", "validate_color": "red"},
370-
{"type": "hidden", "name": "user_id", "value": "place id here"},
371-
{"type": "hidden", "name": "csrf_token", "value": "place token here"},
372+
{"type": "hidden", "name": "resource_id", "value": "1234"},
372373
{"name": "confirm", "label": "Please type \"sensitive resource\" here to confirm the deletion", "required": true}
373374
]')),
374375
('form', 'This example illustrates the use of custom validation buttons and half-width fields.',
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
INSERT INTO sqlpage_functions (
2+
"name",
3+
"introduced_in_version",
4+
"icon",
5+
"description_md"
6+
)
7+
VALUES (
8+
'protocol',
9+
'0.17.1',
10+
'network',
11+
'Returns the protocol that was used to access the current page.
12+
13+
This can be either `http` or `https`.
14+
15+
This is useful to generate links to the current page.
16+
17+
### Example
18+
19+
```sql
20+
select ''text'' as component,
21+
sqlpage.protocol() || ''://'' || sqlpage.header(''host'') || sqlpage.path() as contents;
22+
```
23+
24+
will return `https://example.com/example.sql`.
25+
26+
> Note that the path is URL-encoded. The protocol is resolved in this order:
27+
> - `Forwarded` header
28+
> - `X-Forwarded-Proto` header
29+
> request target / URI
30+
');

src/webserver/database/sql_pseudofunctions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub(super) enum StmtParam {
3838
ReadFileAsText(Box<StmtParam>),
3939
ReadFileAsDataUrl(Box<StmtParam>),
4040
Path,
41+
Protocol,
4142
}
4243

4344
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -91,6 +92,7 @@ pub(super) fn func_call_to_param(func_name: &str, arguments: &mut [FunctionArg])
9192
"version" => StmtParam::SqlPageVersion,
9293
"variables" => parse_get_or_post(extract_single_quoted_string_optional(arguments)),
9394
"path" => StmtParam::Path,
95+
"protocol" => StmtParam::Protocol,
9496
"uploaded_file_path" => extract_single_quoted_string("uploaded_file_path", arguments)
9597
.map_or_else(StmtParam::Error, StmtParam::UploadedFilePath),
9698
"read_file_as_text" => StmtParam::ReadFileAsText(Box::new(extract_variable_argument(
@@ -288,6 +290,7 @@ pub(super) fn extract_req_param_non_nested<'a>(
288290
StmtParam::Literal(x) => Some(Cow::Owned(x.to_string())),
289291
StmtParam::AllVariables(get_or_post) => extract_get_or_post(*get_or_post, request),
290292
StmtParam::Path => Some(Cow::Borrowed(&request.path)),
293+
StmtParam::Protocol => Some(Cow::Borrowed(&request.protocol)),
291294
StmtParam::UploadedFilePath(x) => request
292295
.uploaded_files
293296
.get(x)

src/webserver/http_request_info.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use tokio_stream::StreamExt;
2424
#[derive(Debug)]
2525
pub struct RequestInfo {
2626
pub path: String,
27+
pub protocol: String,
2728
pub get_variables: ParamMap,
2829
pub post_variables: ParamMap,
2930
pub uploaded_files: HashMap<String, TempFile>,
@@ -39,6 +40,7 @@ pub(crate) async fn extract_request_info(
3940
app_state: Arc<AppState>,
4041
) -> RequestInfo {
4142
let (http_req, payload) = req.parts_mut();
43+
let protocol = http_req.connection_info().scheme().to_string();
4244
let config = &app_state.config;
4345
let (post_variables, uploaded_files) = extract_post_data(http_req, payload, config).await;
4446

@@ -73,6 +75,7 @@ pub(crate) async fn extract_request_info(
7375
cookies: param_map(cookies),
7476
basic_auth,
7577
app_state,
78+
protocol,
7679
}
7780
}
7881

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
select 'text' as component,
2+
CASE sqlpage.protocol()
3+
WHEN 'http' THEN 'It works !'
4+
ELSE 'It failed ! Expected "http", got "' || sqlpage.protocol() || '"".'
5+
END
6+
AS contents;

0 commit comments

Comments
 (0)