Skip to content

Commit

Permalink
new function: sqlpage.protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
lovasoa committed Dec 9, 2023
1 parent 3bc76da commit 005180d
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Fix bad contrast in links in custom page footers.
- 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.
- 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.
- 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.

## 0.17.0

Expand Down
52 changes: 26 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions examples/official-site/safety.sql
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ However, if you implement your own session management system using the [`cookie`
you should be careful to follow the [OWASP session management best practices](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#cookies).
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.
## Protection against [CSRF attacks](https://en.wikipedia.org/wiki/Cross-site_request_forgery)
The recommended way to store session tokens for user authentication
in SQLPage is to use the [`cookie` component](/documentation.sql?component=cookie#component).
All cookies set by SQLPage have the `SameSite` attribute set to `strict` by default,
which means that they will only be sent to your website if the user is already on your website.
An attacker cannot make a user''s browser send a request to your website from another (malicious)
website, and have it perform an action on your website in the user''s name,
because the browser will not send the cookies to your website.
SQLPage differentiates between POST variables (accessed with the `:variable` syntax), and
variables that can come from URL parameters (accessible with `$variable`).
When a user submits a form, you should use POST variables to access the form data.
This ensures that you only use data that indeed comes from the form, and not from a
URL parameter that could be part of a malicious link.
Advanced users who may want to implement their own csrf protection system can do so
using the [`sqlpage.random_string()`](/functions.sql?function=random_string#function) function,
and the `hidden` input type of the [`form`](/documentation.sql?component=form#component) component.
For more information, see the [this discussion](https://github.com/lovasoa/SQLpage/discussions/148).
## Database connections
SQLPage uses a fixed pool of database connections, and will never open more connections than the ones you
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,11 @@ or to implement more complex flows, such as a multi-step form,
where the user is redirected to a different page after each step.
This can also be used to implement [CSRF protection](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern),
if your website has authenticated users that can perform sensitive actions through forms.
if your website has authenticated users that can perform sensitive actions through simple links.
But note that SQLPage cookies already have the `SameSite=strict` attribute by default, which protects you against CSRF attacks by default in most cases.
', json('[{"component":"form", "validate": "Delete", "validate_color": "red"},
{"type": "hidden", "name": "user_id", "value": "place id here"},
{"type": "hidden", "name": "csrf_token", "value": "place token here"},
{"type": "hidden", "name": "resource_id", "value": "1234"},
{"name": "confirm", "label": "Please type \"sensitive resource\" here to confirm the deletion", "required": true}
]')),
('form', 'This example illustrates the use of custom validation buttons and half-width fields.',
Expand Down
30 changes: 30 additions & 0 deletions examples/official-site/sqlpage/migrations/27_protocol.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
INSERT INTO sqlpage_functions (
"name",
"introduced_in_version",
"icon",
"description_md"
)
VALUES (
'protocol',
'0.17.1',
'network',
'Returns the protocol that was used to access the current page.
This can be either `http` or `https`.
This is useful to generate links to the current page.
### Example
```sql
select ''text'' as component,
sqlpage.protocol() || ''://'' || sqlpage.header(''host'') || sqlpage.path() as contents;
```
will return `https://example.com/example.sql`.
> Note that the path is URL-encoded. The protocol is resolved in this order:
> - `Forwarded` header
> - `X-Forwarded-Proto` header
> request target / URI
');
3 changes: 3 additions & 0 deletions src/webserver/database/sql_pseudofunctions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub(super) enum StmtParam {
ReadFileAsText(Box<StmtParam>),
ReadFileAsDataUrl(Box<StmtParam>),
Path,
Protocol,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -91,6 +92,7 @@ pub(super) fn func_call_to_param(func_name: &str, arguments: &mut [FunctionArg])
"version" => StmtParam::SqlPageVersion,
"variables" => parse_get_or_post(extract_single_quoted_string_optional(arguments)),
"path" => StmtParam::Path,
"protocol" => StmtParam::Protocol,
"uploaded_file_path" => extract_single_quoted_string("uploaded_file_path", arguments)
.map_or_else(StmtParam::Error, StmtParam::UploadedFilePath),
"read_file_as_text" => StmtParam::ReadFileAsText(Box::new(extract_variable_argument(
Expand Down Expand Up @@ -288,6 +290,7 @@ pub(super) fn extract_req_param_non_nested<'a>(
StmtParam::Literal(x) => Some(Cow::Owned(x.to_string())),
StmtParam::AllVariables(get_or_post) => extract_get_or_post(*get_or_post, request),
StmtParam::Path => Some(Cow::Borrowed(&request.path)),
StmtParam::Protocol => Some(Cow::Borrowed(&request.protocol)),
StmtParam::UploadedFilePath(x) => request
.uploaded_files
.get(x)
Expand Down
3 changes: 3 additions & 0 deletions src/webserver/http_request_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use tokio_stream::StreamExt;
#[derive(Debug)]
pub struct RequestInfo {
pub path: String,
pub protocol: String,
pub get_variables: ParamMap,
pub post_variables: ParamMap,
pub uploaded_files: HashMap<String, TempFile>,
Expand All @@ -39,6 +40,7 @@ pub(crate) async fn extract_request_info(
app_state: Arc<AppState>,
) -> RequestInfo {
let (http_req, payload) = req.parts_mut();
let protocol = http_req.connection_info().scheme().to_string();
let config = &app_state.config;
let (post_variables, uploaded_files) = extract_post_data(http_req, payload, config).await;

Expand Down Expand Up @@ -73,6 +75,7 @@ pub(crate) async fn extract_request_info(
cookies: param_map(cookies),
basic_auth,
app_state,
protocol,
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/sql_test_files/it_works_protocol.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
select 'text' as component,
CASE sqlpage.protocol()
WHEN 'http' THEN 'It works !'
ELSE 'It failed ! Expected "http", got "' || sqlpage.protocol() || '"".'
END
AS contents;

0 comments on commit 005180d

Please sign in to comment.