Walidacja imienia i nazwiska dla pola tekstowego

2

Tylko na litość boską, pamiętaj o przetestowaniu przyklejaniu numeru telefonu i NIP z myślnikami. Bo jak ktoś zamiast wpisywać będzie chciał sobie skopiować i wkleić u Ciebie to powinien mieć taką możliwość z perspektywy UX

0

Takie pola zamierzam potraktować takimi regexami:

const PostCodeRegex = /^[0-9]{2}[-][0-9]{3}$/
const NIPRegex = /^[0-9]{10}$/;
const PhoneRegex = /^[0-9]{9,}$/;
0
MrocznyRycerz napisał(a):

Takie pola zamierzam potraktować takimi regexami:

const PostCodeRegex = /^[0-9]{2}[-][0-9]{3}$/
const NIPRegex = /^[0-9]{10}$/;
const PhoneRegex = /^[0-9]{9,}$/;

Zacznij od walidacji tego na backendzie. Dopiero jak to będzie działać już na 100%, wtedy dodaj checki na froncie.

0

Taka mnie myśl naszła w związku z:

Weź na przykład edytor na 4programmers. Możemy tu wpisywać dowolne SQL'e i XSS jakie się nam tylko nie śniły, ale nie zobaczysz nigdy komunikatu "Nie możesz dodać znaku & w poście".

Czy taki komunikat nie świadczy o niskim poziomie profesjonalizmu? Czyli nie wprowadzaj tego i tego, bo apka jest słabo zabezpieczona.

1
MrocznyRycerz napisał(a):

Taka mnie myśl naszła w związku z:

Weź na przykład edytor na 4programmers. Możemy tu wpisywać dowolne SQL'e i XSS jakie się nam tylko nie śniły, ale nie zobaczysz nigdy komunikatu "Nie możesz dodać znaku & w poście".

Czy taki komunikat nie świadczy o niskim poziomie profesjonalizmu? Czyli nie wprowadzaj tego i tego, bo apka jest słabo zabezpieczona.

Nieprawda, nie jest słabo zabezpieczona.
Zabezpieczenie jest gdzie indziej, tam gdzie mam być - jak było już tu tłumaczone. Znaki "groźne" zostają przepakowane tak, że są niegroźne

Nie wyrażam sobie inaczej - bo np w twoim stylu embargo na tagi html, sql itd by blokowało mozliwość dyskusji na te tematy html/sql
Albo przygotowana przez ciebie stronka by uniemożliwiała zakup biletu na MŚ przez mr John O'Hara (bo apostrof wysadza operacje SQL metodą "naiwną", i powinieneś - w swojej filozofii - go odrzucać)

0

Czy to wystarczy jako zabezpieczenie przeciwko XSS?
https://www.php.net/manual/en/function.htmlspecialchars.php

Czytałem jeszcze o takich libkach:
PHP Anti-XSS
HTML Purifier
htmLawed

Bo do SQL injction pasuje prepared statements.

Ogólnie pod kątem bezpieczeństwa (nie walidacji) warto coś jeszcze zrobić?

Fajnie pokazane w czym rzecz: https://www.w3schools.com/php/func_string_htmlspecialchars.asp

0

To co sądzicie o tym:
screenshot-20221117180324.png
Formularz przelewu pewnego banku.

0

Jak by ktoś nie widział, to stworzyłem taki mały rozwojowy template:
https://4programmers.net/Forum/Oceny_i_recenzje/365299-template_do_walidacji_danych_formularza

Zastanawiam się teraz, czy samo htmlspecialchars oraz prepared statement wystarczy. Docelowo dane z formularza będą wysyłane na maila oraz zapisywane w bazie danych.

0
MrocznyRycerz napisał(a):

Czy to wystarczy jako zabezpieczenie przeciwko XSS?
https://www.php.net/manual/en/function.htmlspecialchars.php

Czytałem jeszcze o takich libkach:
PHP Anti-XSS
HTML Purifier
htmLawed


MrocznyRycerz napisał(a):

Jak by ktoś nie widział, to stworzyłem taki mały rozwojowy template:
https://4programmers.net/Forum/Oceny_i_recenzje/365299-template_do_walidacji_danych_formularza

Głównie czego potrzebujesz, to:

  • wiedzieć z czego wynika XSS i SqlInjection
  • wiedzieć jaki kod jest na to podatny, a jaki nie

Takie "ślepe" używanie tych narzędzi również jest niebezpieczne.

MrocznyRycerz napisał(a):

Zastanawiam się teraz, czy samo htmlspecialchars oraz prepared statement wystarczy. Docelowo dane z formularza będą wysyłane na maila oraz zapisywane w bazie danych.

Pokaż kod.

0

sendForm -> getInputData -> assignInputData

https://github.com/MrocznyRycerz/FormValidateTemplate

Żeby było jasne:

dane z formularza trafiają na backend, skąd rozchodzą się na:

  • formularz PDF generowany po stronie klienta
  • email z potwierdzeniem wysyłany automatycznie
  • zapis do bazy danych

Teoretycznie okazji do XSS tutaj nie ma.

2

Zapis do bazy danych jest scenariuszem w którym może XSS wystąpić jeżeli te dane później wyswietlasz.

Zresztą pozostałe 2 scenariusze też - można wstrzyknąć złośliwy kod do pdf czy maila...

0
MrocznyRycerz napisał(a):

Żeby było jasne:

dane z formularza trafiają na backend, skąd rozchodzą się na:

  • formularz PDF generowany po stronie klienta
  • email z potwierdzeniem wysyłany automatycznie
  • zapis do bazy danych

Teoretycznie okazji do XSS tutaj nie ma.

Jak budujesz e-maila w HTML'u to jest.

0

Czyli użycie htmlspecialchars (lub podobnego) jest zasadne. Ale czy powinienem tym również potraktować informację, którą zapiszę do bazy danych? Czy po prostu potraktować to jako "filtr" generujący kod HTML (strona WWW, email, PDF)?

2
MrocznyRycerz napisał(a):

Czyli użycie htmlspecialchars (lub podobnego) jest zasadne. Ale czy powinienem tym potraktować informację, którą zapiszę do bazy danych? Czy po prostu potraktować to jako "filtr" generujący kod HTML (strona WWW, email, PDF)?

Zasadne - ale kiedy ?
Dane w bazie powinny być czyste - nazbyt często, a nawet masowo widzę pchanie ich zenkapsulowanych encjami html. Najlepszy dowód, że autor nie wiedział co i przed czym zabezpiecza, a o dobrej metodzie mu nie świtało
Sam tą głupotę robiłem jak wszyscy "przez ramię" się uczyliśmy pehapa w l 199x. "insert into ... htmspecjahars(...) " ale to były lata, że pierwszy raz w Polsce B były jakieś stałe łącze internetowe

Funkcji należy używać podczas produkowania outputu przeznaczonego do weba.

1
MrocznyRycerz napisał(a):

Czyli użycie htmlspecialchars (lub podobnego) jest zasadne. Ale czy powinienem tym również potraktować informację, którą zapiszę do bazy danych?

Ależ skąd. Żadnego htmlspecialchars() przy bazie.

MrocznyRycerz napisał(a):

Czy po prostu potraktować to jako "filtr" generujący kod HTML (strona WWW, email, PDF)?

htmlSpecialChars() używasz wtedy, jak łączysz plain text z HTMLem.

Np:

$name = $_GET['name']; // przychodzi imię plaintextem, np "Marek"

$image = "<img src='image.jpg'/>"; // html, np markup z obrazkiem

$name . $image; // ŹLE, nie wolno plaintext'a z HTML'em

htmlSpecialChars($name) . $image; // ok

Podobnie jest z SQL'em

$name = $_GET['name']; // przychodzi imię plaintextem, np "Marek"

$query = "SELECT * FROM table WHERE imie="; // sql, np query z selectem

$query . $name; // ŹLE, nie wolno plaintext'a z SQL'em

$quuery . mysql_real_escape_string($name); // ok
MrocznyRycerz napisał(a):

Czyli użycie htmlspecialchars (lub podobnego) jest zasadne. Ale czy powinienem tym również potraktować informację, którą zapiszę do bazy danych?

Ogólnie, zawsze jak łączysz plaintekst z jakimś formatem, to musisz go poprawnie zaenkodować. Tak samo jest np z formatem JSON, nie możesz zrobić np tak:

$name = $_GET['name']; // przychodzi imię plaintextem, np "Marek"

$json = "{'klucz': $name}"; // źle

tylko musisz zaenkodować odpowiednio ten plaintext w formacie:

$name = $_GET['name']; // przychodzi imię plaintextem, np "Marek"

$json = "{'klucz': " . json_encode($name) . "}";

Jesli niepoprawnie połączysz plaintext z jakimś formatem (np HTML, SQL, JSON), to ten plaintext zostanie zinterpretowany jak ten format (nie dosłownie, tylko jako znaki specjalne - < w HTML, " i -- w SQL, { i [ w JSON), i albo spowoduje to uszkodzenie danych, albo w skrajnych przypadkach XSS i SQLInjection.

Takie przypadki można mnożyć, np z regexpami nie możesz zrobić tak:

$name = $_GET['name']; // przychodzi imię plaintextem, np "Marek"

$pattern = "/\w+$name/"; // źle, $name jest plaintextem, więc trzeba go zaenkodować

$pattern = "/\w+" . preg_quote($name) . "/"; // okej

W skrócie:

  • Można łączyć HTML+HTML
  • Można łączyć PlainText + PlainText
  • Można łączyć SQL+SQL
  • Można łączyć Regex+Regex
  • HTML+PlainText można, pod warunkiem że zrobisz htmlSpecialChars(PlainText)
  • SQL + PlainText można, pod warunkiem że zrobisz mysql_real_escape_string()
  • JSON+PlainText można, pod warunkiem że zrobisz json_encode()
  • Regexp+PlainText można, pod warunkiem że zrobisz preg_quote()
1
MrocznyRycerz napisał(a):

sendForm -> getInputData -> assignInputData

https://github.com/MrocznyRycerz/FormValidateTemplate

Uwagi co do kodu:

  • PHP:
    • Używasz dużo require_once(), na takim poziomie to nie ma sensu, ja na Twoim miejscu bym wszystko dał do jednego pliku
    • Polecam nie zostawiać domykającego ?> na końcu pliku. ?> to jest to samo co echo, jak niechcący zostawisz gdzieś biały znak i ustawis header() to poleci "cannot modify header information".
  • HTML:
    • Nie ma czegoś takiego jak date-, Tobie chodziło o data-?
    • <label for> w for ma być odpowiedni id input'a, Ty dałeś name.
  • JS:
    • Nie pisze się ; za klamerką zamykającą }, są niepotrzebne, powinieneś je wywalić.
    • Używaj const zamiast let.

Ja bym na Twoim miejscu usunął wszystkie pliki .php które masz, i zamiast nich dał to:

<?php

function fieldsPresent(array $fields)
{
    foreach ($fields as $fieldName) {
        if (!isSet($_POST[$fieldName])) {
            return false;
        }
    };
    return true;
}

if (!fieldsPresent(["CompanyName", "PhoneNumber", "NIPNumber"])) {
    header("refresh:1; url=form.html");
    return;
}

$companyName = $_POST["CompanyName"];
$phoneNumber = $_POST["PhoneNumber"];
$nipNumber = $_POST["NIPNumber"];
?>
<html>
<body>
    <p>Company name: <?= htmlSpecialChars($companyName) ?></p>
    <p>Phone number: <?= htmlSpecialChars($phoneNumber) ?></p>
    <p>NIP: <?= htmlSpecialChars($nipNumber) ?></p>
</body>
</html>

Jeśli nie masz włączonego short_open_tag to zamiast <?= musisz dać <?php echo.

0
Riddle napisał(a):

Uwagi co do kodu:

  • PHP:
    • Używasz dużo require_once(), na takim poziomie to nie ma sensu, ja na Twoim miejscu bym wszystko dał do jednego pliku
    • Polecam nie zostawiać domykającego ?> na końcu pliku. ?> to jest to samo co echo, jak niechcący zostawisz gdzieś biały znak i ustawis header() to poleci "cannot modify header information".
  • HTML:
    • Nie ma czegoś takiego jak date-, Tobie chodziło o data-?
    • <label for> w for ma być odpowiedni id input'a, Ty dałeś name.
  • JS:
    • Nie pisze się ; za klamerką zamykającą }, są niepotrzebne, powinieneś je wywalić.
    • Używaj const zamiast let.

Ja bym na Twoim miejscu usunął wszystkie pliki .php które masz, i zamiast nich dał to:

Dzięki za uwagi, wdrożyłem je (później zrobię update w repo).

Skoro ta apka ma robić 3 rzeczy (generowanie PDF, wysłanie maila, operacje na bazie danych), to może lepiej zrobić to w ten sposób, że każda z tych 3 rzeczy to osobny skrypt? A główny, odpalany Submitem wyglądałby tak (docelowo POSTem ma przychodzić około 30 zmiennych):

<?php

// Check if all Input Data is present //

$FormFields = [
    "CompanyName",
    "PhoneNumber",
    "NIPNumber"
];

function fieldsPresent($fields) {
    foreach ($fields as $fieldName) {
        if (!isSet($_POST[$fieldName])) {
            return false;
        }
    };
    return true;
}

if (!fieldsPresent($FormFields)) {
    header("refresh:1; url=form.html");
    return;
}

// Assign Input Data //

$CompanyName = $_POST["CompanyName"];
$PhoneNumber = $_POST["PhoneNumber"];
$NIPNumber = $_POST["NIPNumber"];

// require_once("generatePDF.php");
// call function to generate PDF

// require_once("sendEmail.php");
// call function to send email
?>

<html>
<body>
    <p>Company name: <?php echo htmlSpecialChars($CompanyName) ?></p>
    <p>Phone number: <?php echo htmlSpecialChars($PhoneNumber) ?></p>
    <p>NIP: <?php echo htmlSpecialChars($NIPNumber) ?></p>
</body>
</html>

Czyli jeden skrypt odpowiedzialny za jeden task, który wygodnie będę mógł edytować w razie potrzeby i odłączać/dołączać do głównego.

0

Zacząłem wdrażać mój template na testowym serwerze i wykryłem problem z tą funkcją:

function fieldsPresent($fields) {
    foreach ($fields as $fieldName) {
        if (!isSet($_POST[$fieldName])) {
            return false;
        }
    };
    return true;
}

Jeżeli wywołam skrypt PHP wpisując URL, to zachowa się on zgodnie oczekiwaniem. Czyli jeżeli nic nie przyjdzie POSTem, to dostanę false. Ale jeżeli skrypt odpalę przyciskiem Submit i dodatkowo wyłączę walidację JS, to POSTem przyjdzie "", czyli funkcja zwróci true. W sumie nic zaskakującego.

Jest jakiś lepszy sposób na rozwiązanie tego oprócz poniższych?

if (!isSet($_POST[$fieldName]) || ($_POST[$fieldName] === ""))

if (!isSet($_POST[$fieldName]) || ($_POST[$fieldName].length <= 0))

0
MrocznyRycerz napisał(a):

Zacząłem wdrażać mój template na testowym serwerze i wykryłem problem z tą funkcją:

function fieldsPresent($fields) {
    foreach ($fields as $fieldName) {
        if (!isSet($_POST[$fieldName])) {
            return false;
        }
    };
    return true;
}

Jeżeli wywołam skrypt PHP wpisując URL, to zachowa się on zgodnie oczekiwaniem. Czyli jeżeli nic nie przyjdzie POSTem, to dostanę false. Ale jeżeli skrypt odpalę przyciskiem Submit i dodatkowo wyłączę walidację JS, to POSTem przyjdzie "", czyli funkcja zwróci true. W sumie nic zaskakującego.

Jest jakiś lepszy sposób na rozwiązanie tego oprócz poniższych?

if (!isSet($_POST[$fieldName]) || ($_POST[$fieldName] === ""))

if (!isSet($_POST[$fieldName]) || ($_POST[$fieldName].length <= 0))

To zależy od tego czy chcesz traktować puste wartości jako poprawne, czy niepoprawne. Ogóle brak jakiegoś pola to jest jeden przypadek, ale istniejące pole z pustą wartością to coś innego. Dla niektórych pól, pusta wartość jest niepoprawna, jak np First name albo Address, ale dla innych może już być poprawna, np "numer mieszkania" jeśli ktoś mieszka w domu jednorodzinnym.

Jeśli chcesz uznać wszystkie puste wartości za niepoprane, to tak:

function fieldsPresent($fields) {
    foreach ($fields as $fieldName) {
        if (!isSet($_POST[$fieldName])) {
            return false;
        }
        if ($POST[$fieldName] === '') {
            return false;
        }
    };
    return true;
}

Ale moim zdaniem to jest słaby pomysł. Powinieneś traktować puste wartości inaczej niż brakujące wartości i obsłużyć je osobno.

0
Riddle napisał(a):

puste wartości inaczej niż brakujące wartości i obsłużyć je osobno.

Na przykład wypełnić puste pole komunikatem "proszę wypełnić to pole".

0

Przy okazji nauczyłem się jak z poziomu PHP sprawdzić status checkboxa:

if (isset($_POST["checkboxFieldnName"])) {
    $checkboxStatus = "set";
} else {
    $checkboxStatus = "empty";
}

Przesyłanie value inputa nic nie da. Jeżeli jest odhaczone, to PHP wywala błąd bodajże "Invalid index".

Learned something new again...

1 użytkowników online, w tym zalogowanych: 0, gości: 1