2017-05-11 1 views
5

Ich schreibe eine Website, die ein UserManagement-System implementiert, und ich frage mich, welche Best Practices bezüglich der Formularverarbeitung ich berücksichtigen muss.Best Practices Formularverarbeitung mit Express

Vor allem Leistung, Sicherheit, SEO und User Experience sind mir wichtig. Als ich daran arbeitete, stieß ich auf ein paar Fragen und ich fand keinen vollständigen Knoten/Expresscode-Ausschnitt, wo ich alle meine unten stehenden Fragen herausfinden konnte.

Anwendungsfall: Jemand wird den Geburtstag seines Profils aktualisieren. Im Moment mache ich eine POST-Anfrage an dieselbe URL, um das Formular auf dieser Seite zu bearbeiten, und die POST-Anfrage antwortet mit einer 302-Weiterleitung auf die gleiche URL.

Allgemeine Fragen über die Formularverarbeitung:

  1. Sollte ich eine POST-Anforderung + 302 umleiten für Formularverarbeitung oder lieber etwas anderes wie eine AJAX-Anforderung?
  2. Wie soll ich mit ungültigen FORM-Anfragen umgehen (z. B. ungültige Anmeldung oder E-Mail-Adresse wird bereits bei der Anmeldung verwendet)?

Express spezifische Fragen über die Formularverarbeitung:

  1. Ich gehe davon aus, bevor irgendetwas in meine DB Einsetzen Ich brauche alle Formularfelder auf der Serverseite zu sanieren und zu validieren . Wie würdest du das machen?

  2. Ich habe ein paar Dinge über CSRF gelesen, aber ich habe noch nie einen CSRF-Schutz implementiert. Ich würde mich freuen, dass im Code-Ausschnitt auch

  3. Ich muss mich um andere mögliche Sicherheitslücken kümmern bei der Verarbeitung von Formularen mit Express?

Beispiel HTML/Mops:

form#profile(method='POST', action='/settings/profile') 
    input#profile-real-name.validate(type='text', name='profileRealName', value=profile.name) 
    label(for='profile-real-name') Name 

    textarea#profile-bio.materialize-textarea(placeholder='Tell a little about yourself', name='profileBio') 
     | #{profile.bio} 
    label(for='profile-bio') About 

    input#profile-url.validate(type='url', name='profileUrl', value=profile.bio) 
    label(for='profile-url') URL 

    input#profile-location.validate(type='text', name='profileLocation', value=profile.location) 
    label(for='profile-location') Location 

    .form-action-buttons.right-align 
     a.btn.grey(href='' onclick='resetForm()') Reset 
     button.btn.waves-effect.waves-light(type='submit') 

Beispiel Strecke Handlers:

router.get('/settings/profile', isLoggedIn, profile) 
router.post('/settings/profile', isLoggedIn, updateProfile) 

function profile(req, res) { 
    res.render('user/profile', { title: 'Profile', profile: req.user.profile }) 
} 

function updateProfile(req, res) { 
    var userId = req.user._id 
    var form = req.body 
    var profile = { 
     name: form.profileRealName, 
     bio: form.profileBio, 
     url: form.profileUrl, 
     location: form.profileLocation 
    } 

    // Insert into DB 
} 

Hinweis: Ein kompletter Code-Schnipsel, die Pflege aller Form der Verarbeitung nimmt am besten Praktiken, die an das gegebene Beispiel angepasst sind, werden sehr geschätzt. Mir geht es gut mit jeder öffentlich verfügbaren Express-Middleware.

Antwort

2

Sollte ich eine POST-Anforderung + 302-Umleitung für die Formularverarbeitung oder lieber etwas anderes wie eine AJAX-Anforderung?

Keine, Best Practice für einen guten User Experience seit 2004 oder so (im Grunde seit gmail gestartet) Formularübermittlung via AJAX waren und nicht Web 1.0 ganzseitige Last FORMULARPLZ. Insbesondere ist es weniger wahrscheinlich, dass die Fehlerbehandlung über AJAX Ihren Benutzer auf einer Dead-End-Browserfehlerseite belässt und dann Probleme mit der Zurück-Schaltfläche verursacht. Der AJAX sollte in diesem Fall eine HTTP-PATCH-Anfrage senden, um am semantisch korrekt zu sein, aber POST oder PUT werden ebenfalls die Aufgabe erledigen.

Wie soll ich behandel ungültige FORM-Anfragen (zB ungültige Login oder E-Mail-Adresse ist bereits im Einsatz bei der Anmeldung)?

Ungültige Benutzereingaben in einer HTTP 400 Bad Request Statuscode Reaktion mit dem entsprechenden Angaben über die spezifischen Fehler (n) in einem JSON Antworttext führen sollen (das Format variiert je nach Anwendung, aber entweder eine allgemeine Nachricht oder die Feld-by -Feld-Fehler sind häufige Themen)

Für E-Mails, die bereits verwendet werden, verwende ich den HTTP-Status 409 Conflict als eine besondere Variante der allgemeinen schlechten Anfrage Payload.

Ich gehe davon aus, bevor irgendetwas in meine DB Einsetzen Ich brauche alle Formularfelder auf der Serverseite zu sanieren und zu validieren. Wie würdest du das machen?

Absolut. Es gibt viele Werkzeuge. Ich definiere allgemein ein Schema für eine gültige Anfrage in JSON Schema und benutze eine Bibliothek von npm, um das zu validieren, wie is-my-json-valid oder ajv. Insbesondere empfehle ich, so streng wie möglich zu sein: lehne falsche Typen ab, oder erzwinge Typen, wenn du musst, entferne unerwartete Eigenschaften, benutze kleine, aber vernünftige Stringslängenbeschränkungen und strikte reguläre Ausdrucksmuster für Strings, wenn du kannst DB-Bibliothekseigenschaft verhindert Injektionsangriffe.

las ich einige Dinge über CSRF, aber ich habe noch nie einen CSRF-Schutz implementiert.

Die OWSAP Node Goat Project CSRF Exercise ist ein guter Ort mit einer anfälligen Anwendung zu starten, zu verstehen und diese Sicherheitsanfälligkeit ausnutzen, dann das Update implementieren (in diesem Fall mit einer einfachen Integration der express.csrf() Middleware.

Muss ich Pflege von anderen möglichen Schwachstellen ergreifen müssen, wenn Formulare mit Express Verarbeitung?

Ja im Allgemeinen müssen Anwendungsentwickler sicher verstehen und aktiv codieren. Es gibt eine Menge Material darüber, aber es muss besondere Sorgfalt darauf verwendet werden, wenn Benutzereingaben in Datenbankabfragen, Subprozess-Laichungen oder in HTML-Dateien zurückgeschrieben werden. Solide Abfragebibliotheken und Vorlagen-Engines werden den Großteil der Arbeit hier erledigen, Sie müssen nur die Mechanismen und potentielle Orte kennen, an denen sich bösartige Benutzereingaben einschleusen könnten (wie Bilddateinamen usw.).

+0

Vielen Dank, dass Sie sich die Zeit genommen haben. Stört es Sie, wenn Sie ein reales Code-Beispiel zeigen, das zeigt, wie Sie ein Formular sanieren und validieren? Das würde mir helfen, Ihre Herangehensweise zu verstehen. Ich benutze Mungo, falls du dich fragst. – kentor

+0

Ich mag Mungo ziemlich viel nicht, so leid nein. –

1

Ich bin sicher kein Express-Experte, aber ich denke, dass ich mindestens 1 # beantworten kann:

Sie sollten die Post/Redirect/Get Muster folgen Web-Entwicklung, um doppelte Form vorzubeugen. Ich habe gehört, eine 303-Redirect ist der richtige http-Statuscode für die Weiterleitung von Formulareinreichungen.

Ich verarbeite Formulare mit der POST-Route und sobald ich fertig bin, trigger ich eine 302-Redirect.

Ab # 3 empfehle ich in Express-Validator zu schauen, der hier gut eingeführt wird: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms.Es ist eine Middleware, die Sie so zu validieren und sanieren erlaubt:

req.checkBody('name', 'Invalid name').isAlpha(); 
req.checkBody('age', 'Invalid age').notEmpty().isInt(); 
req.sanitizeBody('name').escape(); 

ich daher die Antwort auf einen Kommentar nicht in der Lage war, obwohl es keine vollständige Antwort ist. Ich dachte nur, es könnte dir helfen.

1

Wenn Benutzererfahrung etwas ist, über das Sie nachdenken, ist eine Seitenumleitung ein starkes Nein. Es ist wichtig, einen reibungslosen Ablauf für die Besucher Ihrer Website zu gewährleisten, um Stürze zu vermeiden, und da Formulare nicht so ein Vergnügen sind, zu füllen, ist die Erleichterung ihrer Verwendung vorrangig. Sie möchten die Seite nicht erneut laden, die möglicherweise bereits einige Zeit zum Laden benötigt, um eine Fehlermeldung anzuzeigen. Sobald das Formular gültig ist und Sie das Benutzer-Cookie erstellt haben, ist eine Umleitung in Ordnung, auch wenn Sie Dinge in der Client-App tun könnten, um dies zu verhindern, aber das ist außerhalb des Bereichs.

Wie von Levent angegeben, sollten Sie überprüfen, express-validator, die die etablierte Lösung für diese Art von Zweck ist.

req.check('profileRealName', 'Bad name provided').notEmpty().isAlpha() 
req.check('profileLocation', 'Invalid location').optional().isAlpha(); 

req.getValidationResult().then(function (result) { 
    if (result.isEmpty()) { return null } 
    var errors = result.array() 
    // [ 
    // { param: "profileRealName", msg: "Bad name provided", value: ".." }, 
    // { param: "profileLocation", msg: "Invalid location", value: ".." } 
    // ] 
    res.status(400).send(errors) 
}) 
.then(function() { 
    // everything is fine! insert into the DB and respond.. 
}) 

Von was es aussieht, kann ich davon ausgehen, dass Sie MongoDB verwenden. In Anbetracht dessen würde ich eine ODM wie Mongoose empfehlen. Dadurch können Sie Modelle für Ihre Schemas definieren und Einschränkungen direkt auf sie anwenden, damit das Modell diese Art von redundanten Validierungen für Sie übernimmt.

Zum Beispiel kann ein Modell für Ihre Benutzer könnte sein

var User = new Schema({ 
    name: { type: String, required: [true, 'Name required'] }, 
    bio: { type: String, match: /[a-z]/ }, 
    age: { type: Number, min: 18 }, // I don't know the kind of site you run ;) 
}) 

Mit diesem Schema auf Ihrer Route

var user = new User({ 
    name: form.profileRealName, 
    bio: form.profileBio, 
    url: form.profileUrl, 
    location: form.profileLocation 
}) 

user.save(function (err) { 
    // and you could grab the error here if it exists, and react accordingly 
}); 

suchen, wie würden Sie sehen eine ziemlich cool api bietet, die Sie sollten ungefähr in their docs lesen, wenn Sie mehr wissen möchten.

Über CRSF, sollten Sie csurf installieren, die ziemlich gute Anweisungen und Beispielanwendungen auf ihrem readme hat.

Danach sind Sie ziemlich gut zu gehen, es gibt nicht viel mehr ich getrennt denken kann, um sicherzustellen, dass Sie auf dem Laufenden mit Ihren kritischen Abhängigkeiten bleiben, falls ein 0-Tage auftritt, zum Beispiel the one im Jahr 2015 mit JWTs, aber das ist immer noch ein bisschen selten.