Node.js bezpieczeństwo

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!

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.

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.

1
  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?

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!

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.
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}); ?

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. *
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.. :)

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