zapytanie typu REST - czy da się bez frameworka

0

Chcę zaimplementować takie coś, że jak w okno przeglądarki wpiszę pokaz.php/tabela_A, to wyświetlą mi się rekordy z tabeli A. Analogicznie dla tabel B, C itd.
Czy takie coś można uzyskać bez frameworka?

1

Tak, ale tak nie rób, bo to nic nie ma wspólnego z bezpieczeństwem aplikacji xD

EDIT: Chodzi mi o podawanie nazwy tabelki w urlu.

0

A co jeżeli na początku sprawdzam flagę (zmienna sesyjna), czy jestem zalogowany? O tym piszesz? A może chodzi o to, że w url ktoś może wpisać jakieś sql injection.

4

Jak chcesz wyświetlić userowi jakieś dane, to zrób se CRUDa do tych tabelek, które chcesz + walidacja danych i jakiś ACL. To co proponujesz to wygląda jak próba wyświetlenia zawartości każdej wybranej tabelki, jeśli poda się jej nazwę. A tego na 100% nie chcesz.

2

Zakładam, że autorowi chodzi właśnie o WŁASNE API, które w mniejszym / większym stopniu jakoś zabezpieczy.

@kosmonauta80 Ja powiem tak, jeżeli chcesz przerzucić na siebie ryzyko bezpieczeństwa działania takiego API to jak najbardziej możesz sam pisać. Zauważ jednak, że framework ma już gotowe TO, co Ty dopiero będziesz musiał napisać ponownie (od razu zaznaczam, że framework jest testowany przez większą liczbę użytkowników i to co się Tobie wydaje bezpieczne nie zawsze takie będzie)

2
kosmonauta80 napisał(a):

Chcę zaimplementować takie coś, że jak w okno przeglądarki wpiszę pokaz.php/tabela_A, to wyświetlą mi się rekordy z tabeli A. Analogicznie dla tabel B, C itd.

Czy takie coś można uzyskać bez frameworka?

Opisz najpierw po co chciałbyś zrobić coś takiego?

  • Próbujesz dodać kilka endpointów do swojej aplikacji? Jeśli tak, to zastanów się czy na pewno parametr z URL pokaz.php/<nazwa>, musi być taki sam jak nazwa tabeli SELECT * FROM nazwa, czy może to tylko przypadek? Może dobrze by było gdyby Twoj zasób pokaz.php/accounts na prawdę brał z tabeli users? To że coś wydaje się takie same na pierwszy rzut oka nie znaczy że jest.

  • Potrzebujesz sprawdzić swoją bazę lokalnie, na cele testów, albo po prostu podejrzeć co tam masz?

    Jeśli tak, to zainteresuj się narzędziem PhpMyAdmin, on pozwala podejrzeć lokalną bazę (albo i nawet nie lokalnę) w bardzo fajny sposób.
    screenshot-20210906172729.png

  • Czy może chcesz wyświetlać różne dane w różny sposób? Jeśli tak, to zastanów się czy funkcja która filtruje recordy albo mapuje w Twoim kodzie źródłowym nie byłaby odpowiedniejsza.

  • Czy może próbujesz zrobić coś jeszcze innego, masz jakiś inny pomysł?

Jeśli nie powiesz nam co próbujesz zrobić, to ciężko będzie Ci pomóc.

0
serek napisał(a):

Tak, ale tak nie rób, bo to nic nie ma wspólnego z bezpieczeństwem aplikacji xD

@serek **Co za bzdura! ** Co ma przygotowanie prostego serwera resto'wego bez wykorzystywania framework z bezpieczeństwem?
Myślę, że aby pobrać dane z kilku tabel to nie wykorzystywanie framework jest nawet bezpieczniejsze bo masz mniej potencjalnych miejsc na luki.

1
katakrowa napisał(a):
serek napisał(a):

Tak, ale tak nie rób, bo to nic nie ma wspólnego z bezpieczeństwem aplikacji xD

@serek **Co za bzdura! ** Co ma przygotowanie prostego serwera resto'wego bez wykorzystywania framework z bezpieczeństwem?
Myślę, że aby pobrać dane z kilku tabel to nie wykorzystywanie framework jest nawet bezpieczniejsze bo masz mniej potencjalnych miejsc na luki.

Nie mam na myśli frameworka lub jego braku. Tylko to, że gość chce podawać w urlu nazwy tabelek. Idealny sposób, by pokazać za dużo niechcianym osobom.

W sumie widzę, że nie napisałem tego pierwszego posta zbyt zrozumiale^^

1
serek napisał(a):
katakrowa napisał(a):
serek napisał(a):

Tak, ale tak nie rób, bo to nic nie ma wspólnego z bezpieczeństwem aplikacji xD

@serek **Co za bzdura! ** Co ma przygotowanie prostego serwera resto'wego bez wykorzystywania framework z bezpieczeństwem?
Myślę, że aby pobrać dane z kilku tabel to nie wykorzystywanie framework jest nawet bezpieczniejsze bo masz mniej potencjalnych miejsc na luki.

Nie mam na myśli frameworka lub jego braku. Tylko to, że gość chce podawać w urlu nazwy tabelek. Idealny sposób, by pokazać za dużo niechcianym osobom.

W sumie widzę, że nie napisałem tego pierwszego posta zbyt zrozumiale^^

Gościu, ale czemu nie rozumiesz, że autor wątku nie opisał co on chce zrobić. Jeśli pisze np. klienta bazy danych, to musi wsadzić nazwę tabelki w URL. Albo jak pisze server-side proxy - to nazwy tabelek muszą być parametryzowane. Może chce po prostu zdebugować, i trzeba mu polecić coś jak phpMyAdmin. Nie wiesz co on chce zrobić.

Jedyną senswoną odpowiedzią tutaj jest poproszenie autora wątku @kosmonauta80 żeby sprecyzował co chce osiągnąć; i dopiero wtedy możemy mu pomóc.

0

Chcę zrobić tak:
a) mam menu z różnymi pozycjami
b) po kliknięciu na daną pozycję JS wyświetla w nowej zakładce stronę, a właściwie skrypt PHP
c) skrypt na podstawie parametru, który chcę przekazać, a tym parametrem jest nazwa tabeli, ma wyświetlić zawartość tej tabeli (czyli łączy się, a potem echo)

Patrzyłem na stacoverflow i widzę, że window.open (z JS) i dodatnie do tego parametru poprzez POST nie jest takie trywialne. Albo dużo rzeźbienia to wymaga, albo użycia mało eleganckiego sposobu.

I faktycznie, w URL nie chciałbym za dużo pokazywać. Dlatego POST wydaje się najlepszy. Dzięki temu użytkownik nie zgadnie nazwy tabeli.

0
kosmonauta80 napisał(a):

I faktycznie, w URL nie chciałbym za dużo pokazywać. Dlatego POST wydaje się najlepszy. Dzięki temu użytkownik nie zgadnie nazwy tabeli.

Zgadnie jak się uprze i wcale nie wymaga to od niego zbyt wielkiej wiedzy :)

kosmonauta80 napisał(a):

Chcę zrobić tak:

a) mam menu z różnymi pozycjami
b) po kliknięciu na daną pozycję JS wyświetla w nowej zakładce stronę, a właściwie skrypt PHP
c) skrypt na podstawie parametru, który chcę przekazać, a tym parametrem jest nazwa tabeli, ma wyświetlić zawartość tej tabeli (czyli łączy się, a potem echo)

Patrzyłem na stacoverflow i widzę, że window.open (z JS) i dodatnie do tego parametru poprzez POST nie jest takie trywialne. Albo dużo rzeźbienia to wymaga, albo użycia mało eleganckiego sposobu.

A czemu poprzez window.open chcesz nową kartę otwierać w przeglądarce? Jak dla mnie to co opisałeś to jest zwykłe przechodzenie poprzez podstrony, które linkowane są w menu głównym :)

0

Działa :D

Kod JS, który wywołuje kliknięcie w menu:

function wyswietlDane()
{
    const adres = 'pokaz.php';
    let formData = new FormData();
    formData.set("do_wyslania'', this.id);

    // I raz
    fetch(adres,
    {
        method: "POST",
        body: formData,
    });

   // II raz
    window.open('pokaz.php','_blank');
}

Kod PHP, który de facto wykonuje się na 2 podejścia:

<?php
    // utworz obiekt PDO i połącz się

    if (isset($_SESSION['odebrane']))
    {
        $userQuery = $db->prepare("SELECT * FROM $_SESSION['odebrane']");
        $userQuery->execute();

        while ($odczyt = $userQuery->fetchObject())
        {
            echo($odczyt->nazwa_parametru.'<br>');
        }
        unset($_SESSION['przekazane_ID']);
    }
    else
    {
        $_SESSION['odebrane'] = $_POST['do_wyslania'];
    }
?>

Wiem...
a) nazwy zmiennych i metod do d**y
b) walidacja danych do d**y
Powyższe "ZrobiSię"

Tylko czy to faktycznie jest REST?

0

I uważasz, że to ochroni przed sprawdzeniem z jakiej tabeli korzystasz?

0

W samym skrypcie PHP finalną nazwę tabelki mogę skleić z tego, co przyszło z JS + dodatkowy człon w nazwie.
A do treści skryptu PHP tak łatwo się nie dostaniesz.

2

@kosmonauta80: To niestety muszę Cię trochę zmartwić bo to nie jest nawet podobne do API. Ba, to jest podobne do... nawet sam nie wiem jak to nazwać. Poświęć chwilę i porównaj coś takiego względem swojego kodu (proszę o nie krytykowanie tego co teraz napiszę, chcę tylko przedstawić swój tok rozumowania :) ):

plik index.php

<?php
$page = $_GET['page'] ?? false;

if ($page) {
   switch $page {
      case 'page_a':
         $tableName = 'nazwa_tabeli_a';
         break;
      case 'page_b':
         $tableName = 'nazwa_tabeli_b';
         break;
      default:
         $tableName = null;
         break;
      }
   if ($tableName) {
   // kod do pobierania danych z bazy z tabeli o nazwie $tableName;
   $result = ''; // tutaj zwracamy wartości z bazy danych
   }
}
?>

<a href='index.php?page=page_a'>Page A</a><br />
<a href='index.php?page=page_b'>Page B</a><br />

<?php
if ($result) {
// wyświetlamy dane $result
}
?>

Bez JS'a i kod robi dokładnie to samo co Twój. Znasz parametr jaki przekazuję i w jaki sposób Ci to pomoże w odgadnięciu nazwy tabeli?

0

W tym co chcesz zrobić w przykładowym kodzie jest jedna rzecz o której warto wspomnieć a druga wprost niebezpieczna.

  1. W sumie nie wiem czy to niebezpieczne ale potencjalnie ułatwiające komuś bardziej zawziętemu dostać się do danych. Chodzi o to, że przekazywanie nazwy tabeli czy to w POST czy GET daje potencjalnemu atakującemu informacje o tym jakie tabele są w bazie. Czy samo to jest niebezpiecznie lub dziurą w bezpieczeństwie... Nie!
    Mamy całą masę systemów w których wiadomo jakie są nazwy tabel i jakie żądania do serwera się do nich dostają a mimo to tego typu rzeczy nikt nie uznaje za dziury. lepiej nazwy tabel na potrzeby API przeindeksować i posługiwać się czymś innym niż nazwą tabeli wprost. Jednak jak wcześniej napisałem to nie jest jakaś poważna luka. Najprawdopodobniejszym z zagrożeń jest to, że ktoś mógłby to wykorzystać do identyfikacji całego systemu lub frameworka aby następnie posłużyć się jakimś gotowym exploitem. Jesli to twój system autorski to ta informacja generalnie gó..o mu da.

  2. Niebezpieczny jest następujący Twojego fragment kodu

        $userQuery = $db->prepare("SELECT * FROM $_SESSION['odebrane']");
        $userQuery->execute();

w szczególności to: "SELECT * FROM $_SESSION['odebrane']" jet to miejsce podatne na ataki typu SQL Injection ( https://www.w3schools.com/sql/sql_injection.asp ).
Jeśli faktycznie chcesz całkowitą dowolność w przekazywaniu do API nazw tabel to lepiej byłoby zrobić to tak:

<?php
  $tableName = $_SESSION['odebrane']"
  $tableName = trim ( $_SESSION['odebrane']" ) ;
  
  // ZAPIS UPROSZCZONY TO JEDYNIE SKRÓT MYŚLOWY A NIE DZIAŁAJĄCY KOD !!!
  // Pobieram listę wszystkich tabel jakie są w bazia danych
  $tableList = $db->prepare("SHOW TABLES");
  $tableList->execute();  
  
  // sprawdzam czy nazwa tabeli z parametru API faktycznie istnieje w naszej bazie
  // przy okazji czy to nie jest jakiś Sql Injection...
  if  ( in_array ( $tableName, $tableList ) ){  
    $userQuery = $db->prepare("SELECT * {FROM $tableName}");
    $userQuery->execute();$   
  }  
  1. Informacyjnie. Zawartość przesyłanych wartości POST i GET są dla potencjalnie zainteresowanego równie łatwo osiągalne za pomocą niemal każdej przeglądarki.
0
katakrowa napisał(a):

W tym co chcesz zrobić w przykładowym kodzie jest jedna rzecz o której warto wspomnieć a druga wprost niebezpieczna.

  1. W sumie nie wiem czy to niebezpieczne ale potencjalnie ułatwiające komuś bardziej zawziętemu dostać się do danych. Chodzi o to, że przekazywanie nazwy tabeli czy to w POST czy GET daje potencjalnemu atakującemu informacje o tym jakie tabele są w bazie. Czy samo to jest niebezpiecznie lub dziurą w bezpieczeństwie... Nie!

To be honest nie do końca się zgadzam, bo nikt przecież nie musi wiedzieć że jego parametr to jest nazwa tabeli.

Czy gdyby chciał zrobić endpoint pokaz.php/users, i miał tabelę users w bazie, to co ma zrobić? Zmienić nazwę tabeli, żeby nie była taka sama jak endpoint? Dopóki nie zrobi z tym czegoś głupiego, jak "SELECT * FROM $_SESSION['odebrane']" to powinno być okej.

0

Jeżeli chodzi o SQL injection, to o ile dobrze rozumiem, stosując PDO poniższy zapis powinien wystarczyć?

        $userQuery = $db->prepare("SELECT * FROM users WHERE login = :login");
        $userQuery->bindValue(':login', $_SESSION['login']);
        $userQuery->execute();

Htmlentities czy filter_input nie są konieczne, prawda?

0
TomRiddle napisał(a):
katakrowa napisał(a):

W tym co chcesz zrobić w przykładowym kodzie jest jedna rzecz o której warto wspomnieć a druga wprost niebezpieczna.

  1. W sumie nie wiem czy to niebezpieczne ale potencjalnie ułatwiające komuś bardziej zawziętemu dostać się do danych. Chodzi o to, że przekazywanie nazwy tabeli czy to w POST czy GET daje potencjalnemu atakującemu informacje o tym jakie tabele są w bazie. Czy samo to jest niebezpiecznie lub dziurą w bezpieczeństwie... Nie!

To be honest nie do końca się zgadzam, bo nikt przecież nie musi wiedzieć że jego parametr to jest nazwa tabeli.

Czy gdyby chciał zrobić endpoint pokaz.php/users, i miał tabelę users w bazie, to co ma zrobić? Zmienić nazwę tabeli, żeby nie była taka sama jak endpoint? Dopóki nie zrobi z tym czegoś głupiego, jak "SELECT * FROM $_SESSION['odebrane']" to powinno być okej.

Przecież napisałem:

  1. W sumie nie wiem czy to niebezpieczne ale potencjalnie ułatwiające komuś bardziej zawziętemu dostać się do danych.
  2. Najprawdopodobniejszym z zagrożeń jest to, że ktoś mógłby to wykorzystać do identyfikacji całego systemu lub frameworka aby następnie posłużyć się jakimś gotowym exploitem. Jesli to twój system autorski to ta informacja generalnie gó..o mu da.

więc albo nie przeczytałeś całego albo proszę wyjaśnij co masz na myśli bo nie rozumiem dlaczego nie do końca się zgadzasz ?

2
kosmonauta80 napisał(a):

Jeżeli chodzi o SQL injection, to o ile dobrze rozumiem, stosując PDO poniższy zapis powinien wystarczyć?

$userQuery = $db->prepare("SELECT * FROM users WHERE login = :login");
$userQuery->bindValue(':login', $_SESSION['login']);
$userQuery->execute();

Tak, to jest poprawne budowanie zapytań.

Htmlentities czy filter_input nie są konieczne, prawda?

Yyyy... a skąd ten pomysł? htmlEntities() służy do składania tekstu i HTML, a filter_input() to wszystko-w-jednym-funkcja PHP, która się nienadaje prawie do niczego.

0

Znacie jakiś dobry przykład SQL injection, za pomocą którego będę mógł przetestować swoje rozwiązanie?

1
kosmonauta80 napisał(a):

Znacie jakiś dobry przykład SQL injection, za pomocą którego będę mógł przetestować swoje rozwiązanie?

Najbardziej popularny to chyba "; DROP DATABASE x; --, albo to samo tylko z apostrofem.

Tak na prawdę musiałbyś pokazać jak kleisz query, bo to od tego zależy.

0

Dokładnie tak, jak w poprzednim poście. Czyli najpierw prepare(), a potem bind().

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