Node.js bezpieczeństwo

Odpowiedz Nowy wątek
2016-11-23 09:18

Rejestracja: 3 lata temu

Ostatnio: 3 lata temu

0

Cześć,

Pracuję na własną aplikacją i chciałbym się dowiedzieć jak najlepiej obsłużyć formularz rejestracji użytkownika z perspektywy bezpieczeństwa.

Mam dwie opcje:

  1. Wykorzystanie ajax i rendering strony internetowej po stronie przeglądarki na podstawie danych zwróconych przez wywołanie asynchroniczne - czy jest to bezpieczne?
  2. Rendering strony po stronie serwera za pomocą express (metoda POST). Wymaga to odświeżenia ekranu przeglądarki (meoda GET). I tu pojawia się moje pytanie. W jaki sposób przywrócić dane wpisane w formularz przez użytkownika po odświeżeniu przeglądarki. Jedną z opcji jest wkorzystanie cookies, ale boję się, że może to być niebezpieczne.

Dziękuję i pozdrawiam!

Pozostało 580 znaków

2016-11-23 09:36

Rejestracja: 4 lata temu

Ostatnio: 2 dni temu

2

Nie wiem czy dobrze zrozumiałem, ale spróbuję dodać swoje 5gr.

  1. Jeżeli masz typowe SPA, to użytkownik i tak ma dostęp do twojego kodu HTML. Ważne, żebyś chronił dostęp do danych, bo to dane są tym, czym musisz chronić. Jeżeli logowanie asynchroniczne się powiedzie powinieneś zwrócić userowi token (JWT), który od tej pory będzie używał do autentykacji podczas każdego requesta. Załóżmy, że user "zhackuje" Twój serwis, albo przez przypadek zobaczy np. dashboard tylko dla zalogowanych, to bez tokena zobaczy tylko sam html (jakieś tabelki), bo do pobrania danych i uzupełnienia nimi tabelek potrzebny jest token. Przykład takiego rozwiązania jest tutaj.

  2. Nie bardzo rozumiem. Jeżeli renderujesz stronę po stronie serwera, to zwracasz już wyrenderowany HTML, a dane populujesz (uzupełniasz nimi formularz) podczas tego procesu.

edytowany 1x, ostatnio: Desu, 2016-11-23 09:37

Pozostało 580 znaków

2016-11-23 10:10

Rejestracja: 3 lata temu

Ostatnio: 3 lata temu

0

Dzięki za odpowiedź.

  1. Obecnie używam passport'a do autentykacji. Myślisz, że to wystarczy?

  2. Proces przebiega następująco:

app.post('/register', function(req, res) {
// uruchamia się po kliknięciu na button. Tu odbywa się pobranie danych z bazy i sprawdzenie czy ten email jest już używany. Jeżeli nie to utwórz konto.

if(err){
res.redirect('/registerform'); //problem pojawia się w tym miejscu, gduż po instrukcji redirect nie posadam już danych wpisanych przez użytkownika. Moge je przekazać za pomocą cookies. Pytanie czy jest to bezpieczne.
}
})

Dzięki!

Desu napisał(a):

Nie wiem czy dobrze zrozumiałem, ale spróbuję dodać swoje 5gr.

  1. Jeżeli masz typowe SPA, to użytkownik i tak ma dostęp do twojego kodu HTML. Ważne, żebyś chronił dostęp do danych, bo to dane są tym, czym musisz chronić. Jeżeli logowanie asynchroniczne się powiedzie powinieneś zwrócić userowi token (JWT), który od tej pory będzie używał do autentykacji podczas każdego requesta. Załóżmy, że user "zhackuje" Twój serwis, albo przez przypadek zobaczy np. dashboard tylko dla zalogowanych, to bez tokena zobaczy tylko sam html (jakieś tabelki), bo do pobrania danych i uzupełnienia nimi tabelek potrzebny jest token. Przykład takiego rozwiązania jest tutaj.

  2. Nie bardzo rozumiem. Jeżeli renderujesz stronę po stronie serwera, to zwracasz już wyrenderowany HTML, a dane populujesz (uzupełniasz nimi formularz) podczas tego procesu.

edytowany 1x, ostatnio: alwaro25, 2016-11-23 10:12

Pozostało 580 znaków

2016-11-23 11:06

Rejestracja: 4 lata temu

Ostatnio: 2 dni temu

  1. Myślę, że tak. Passport ma specjalną strategię do tego typu autentykacji i nazywa się passport-jwt.
  2. Możesz użyć ciacha czy sesji
    req.session.registerAttempt = credentials;
    // .... 
    var login = req.session.registerAttempt && req.session.registerAttempt.login

    ale polecam ustawić tam tylko login, bo po co hasło? @alwaro25 Można też zrobić tak (nie znam express'a, więc podejdź do tego rozwiązania z dystansem):

var express = require('express')
var bodyParser = require('body-parser');
var app = express()

app.use(bodyParser.urlencoded({
  extended: true
}));

app.get('/register', function (req, res) {
  var login = req.query && req.query.login || "";
  res.send(`
    Register form: 
    <form action="/register" method="post">
      <input type="text" name="login" value="${login}">
      <input type="password" name="password">
      <input type="submit" value="Login">
    </form>`
  )
});

app.post('/register', function (req, res) {
  var userExists = true;

  if (userExists) { // Jeżeli istnieje, to nie możemy utworzyć nowego, więc przekierowujemy z powrotem do formularza
    res.redirect(`/register?login=${req.body.login}`);
  }

  // tworzymy usera czy coś tam
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})

Z reszta to jest dobre przy logowaniu, a nie rejestracji. Jak ktoś poda maila, który istnieje to po co uzupełniać go z powrotem?

edytowany 6x, ostatnio: Desu, 2016-11-23 20:35
@shagrin dziwi Cie js po stronie serwera, czy walnąłem jakiegoś babola? - Desu 2016-11-23 12:38

Pozostało 580 znaków

2016-11-23 12:35

Rejestracja: 3 lata temu

Ostatnio: 3 lata temu

0
  1. Do Passporta dołączyłem CSURF jako dodatkowe zabezpieczenie. Mam tylko taką wątpliwość. W dokumentacji npm csurf wskazują żeby przekazać wartość tokenu jako ukryty input <input type="hidden" name="_csrf" value="{{csrfToken}}">. Czy jest to bezpieczne jeżeli bez problemu można zobaczyć wartość tego tokenu w przeglądarce?

  2. Jest to dobre rozwiązanie. Co w przypadku gdy np. użytkownik tworzy większy obiekt posiadający 50 pól?

Dzięki wielkie!

Pozostało 580 znaków

2016-11-23 12:40

Rejestracja: 4 lata temu

Ostatnio: 2 dni temu

0
  1. Dlaczego się nie dowiesz co to jest csrf token? Jak będziesz wiedział do czego to jest, to odpowiesz sobie na pytanie czy szkodzi, że user to widzi, czy nie. http://stackoverflow.com/a/33829607/5761836 :)
  2. To wtedy możesz go zapisać do sesji i w ten sposób przekazać. Spróbuj dobrze pogooglowac, bo aż nie chce mi się wierzyć, żeby nie było łatwiejszego rozwiązania przekazywania parametrów przy redirect, a jak już mówiłem znam node i express tyle o ile.
edytowany 2x, ostatnio: Desu, 2016-11-23 12:42

Pozostało 580 znaków

2016-11-23 16:49

Rejestracja: 12 lat temu

Ostatnio: 1 rok temu

Lokalizacja: Norwegia, Stavanger

0

@Desu zdziwiło mnie to:

Desu napisał(a):
app.get('/register', function (req, res) {
var login = req.query && req.query.login || "";
res.send(`
Register form: 
<form action="/register" method="post">
<input type="text" name="login" value="${login}">
<input type="password" name="password">
<input type="submit" value="Login">
</form>`
)
});

Mieszanie w tym miejscu HTML? Powodzenia w utrzymaniu takich aplikacji..

oraz to:

Desu napisał(a):

app.post('/register', function (req, res) {
var userExists = true;

if (userExists) { // uzytkownik nie istnieje
res.redirect(/register?login=${req.body.login});
}

// tworzymy usera czy coś tam
});



Zakładając, że to ma być sprawdzenie, czy użytkownik o takim loginie istnieje: jeśli istnieje, zwróć tę informację do użytkownika, jaki cel ma res.redirect(`/register?login=${req.body.login}`); ?

Pozostało 580 znaków

2016-11-23 20:32

Rejestracja: 4 lata temu

Ostatnio: 2 dni temu

0

@shagrin
Bardzo słuszna uwaga. Oczywiście, że w prawdziwym projekcie nie powinno się zamieszczać w ten sposób kodu HTML. To miał być prosty przykład, który zadziała po wklejeniu.
Redirect ma na celu ponowne wyświetlenie formularza z wypełnionym loginem (to obsługuje nam GET pod /register), czy też innymi polami. Można by to zrobić w ramach POST pod /register, ale po co?

  • Komentarz też jest trochę mylący, bo odwróciłem logikę i go przez przypadek zostawiłem. *
edytowany 3x, ostatnio: Desu, 2016-11-23 20:34

Pozostało 580 znaków

2016-11-23 20:45

Rejestracja: 12 lat temu

Ostatnio: 1 rok temu

Lokalizacja: Norwegia, Stavanger

1

@Desu

Właśnie to mnie zastanawia: redirect z powrotem do formularza. Co ten biedny użytkownik ma zrobić? Próbuje się zarejestrować a jedyne co się dzieje to.. nic.
Może zamiast redirect lepsze byłoby:

app.post('/register', function (req, res) {
  var userExists = true;

  if (userExists) { // uzytkownik nie istnieje
    res.status(409).send({'error':'Użytkownik o podanym loginie już istnieje'});
  }

  // tworzymy usera czy coś tam
});

I wyświetlenie błędu użytkownikowi? W końcu się dowie, że musi zmodyfikować dane.. :)


edytowany 1x, ostatnio: shagrin, 2016-11-23 21:26
Pokaż pozostałe 7 komentarzy
@LukeJL odnośnie "shut up and take my money" nie dawno mieliśmy na forum dyskusje dot. przechowywania haseł w plain text, bo klient chce mieć do nich dostęp. Chociaż ta 500 nie była moją decyzją, to wydaje się jednak drobiazgiem przy przytoczonym problemie z hasłami, nie sądzisz? - shagrin 2016-11-23 21:17
bardziej mi to przypomina honeypot niż security by obscurity - te pierwsze są skutecznym rozwiązaniem, a zabawa w kotka i myszkę może być zabawna - byleby to nie była jedyna forma zabezpieczenia. - dzek69 2016-11-23 21:22
a kod to 409 - dzek69 2016-11-23 21:23
chociaż może niekoniecznie, sugerując się angielskim, a nie polskim opisem z wiki :p backendem się aż tak nie zajmuję aktualnie :p - dzek69 2016-11-23 21:25
409 faktycznie idealnie pasuje, zrobię edit (This code is used in situations where the user might be able to resolve the conflict and resubmit the request) - shagrin 2016-11-23 21:26

Pozostało 580 znaków

Odpowiedz

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