Android App MySQL Datenbank sicherer Access

  • Java

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Radinator.

    Android App MySQL Datenbank sicherer Access

    Hallo,

    meine Frage lautet wie man am sichersten in einer Java basierten Android App Verbindung zu einer MySQL Datenbank aufbaut um Daten auszulesen.
    Das Problem dabei ist, dass man das Password hart in die App codieren müsste, was bei dekompilierung nur minder gut kommt.
    Im Wesentlichen sind in der DB bisher Login-Daten hinterlegt, die beim Starten der App abgefragt werden sollen.

    Wie macht man das sicher bzw. wie ist das in anderen bekannten Apps realisiert?

    8-) faxe1008 8-)
    Ganz einfach: Mit PHP als Schnittstelle.

    tutorialspoint.com/android/android_php_mysql.htm

    Da ist eine theoretische Funktionsweise. Du solltest aber trotz dieses Beispiels auf maximale Sicherheit pledieren und dich informieren wie du sowohl Clientseitig als auch Serverseitig (PHP) vernünftig absicherst.
    Zum Beispiel spricht da schon mal nichts gegen https/SSL.
    Wenn du mit Credentials die Login Daten eines Users meinst der sich in der App einloggen kann dann ja, wenn du mit Credentials die mySQL Zugangsdaten meinst, dann nein, das wäre tödlich. Das komplette MySQL Gedöns findet auf Basis von PHP statt, heißt die Verbindungsdaten werden in der PHP Datei direkt angegeben.

    Genau, wenn du ein Login System machen möchtest, schickst du Username + Passwort (am besten gehashed) per POST an das PHP Dokument und baust dann deine SQL Queries zusammen.

    ThuCommix schrieb:

    Für mich sieht es so aus, als wär ein REST/SOAP Service genau das richtige für dich. Hast du schon mal Erfahrungen damit gemacht?


    Jo, je nachdem wie groß das Projekt wird, wär's tatsächlich besser sowas durch ein schon dafür entwickeltes Framework zu benutzen. Aber im Grundsatz ist das genau das gleiche.
    Ich hab es jetzt mal ausprobiert und es funktioniert echt hervorragend. Allerdings hab ich mir folgende Frage gestellt.
    Ich möchte mit der Anwendung einen Registrierungsprozess für die Benutzer abbilden der wie folgt aussieht:

    Username, PasswordHash, Email -> API -> API füllt MySQL-Tabelle aus und generiert einen Token für die Aktivierung der in der Aktivierungsmail mitversandt wird.

    Wie kann ich verhindern, dass jemand das Programm dekompliliert, herausfindet wie der Registrierungsbefehl in der API lautet und meinen MySQL Server mit Anfragen überhäuft?

    8-) faxe1008 8-)
    Das ist auch relativ einfach.
    Ich erklär' dir mal wie du das löst.

    Der Benutzer der sich registrieren will, gibt Username, Passwort und Email Adresse in deiner App an.
    Du lässt den Benutzer die Eingabe abschicken. Rufst also anstelle von login.php z.B. eine register.php auf der du die Daten übergibst (das Passwort am besten schon gehashed).
    Im PHP Skript prüfst du dann, ob der Username oder die Email Adresse schon im System registriert ist und machst dementsprechend eine Ausgabe.
    Im Normalfall ist der Benutzer und die Email Adresse frei und trägst den Account in die Datenbank ein.

    Wie du das jetzt mit der Aktivierung machst läuft jetzt nochmal separat ab.
    Du generierst am besten während nach der erfolgreichen Prüfung ob Username und Email noch frei sind, direkt im PHP Skript einen token.
    Wie du das machst ist dir überlassen, wilde Kombination aus Buchstaben und Zahlen reicht da ja eigentlich schon. Kannst dir da ja mal was einfallen lassen ansonsten helf ich dir.
    Dann erstellst du am besten eine neue Tabelle in der Datenbank die du z.B. tbl_Aktivierungen nennst.
    Die Felder sind folgende:

    userId - Fremdschlüssel zur Benutzertabelle.
    token - Der Token des Nutzers.

    So, wenn der Token jetzt generiert wurde in deinem Skript trägst du den Benutzer mit seinen Daten in die Benutzertabelle und den generierten Token in die Aktivierungstabelle.
    Wenn das Einführen erfolgreich war, sendest du dem Benutzer eine Email auch direkt im selben PHP Skript wo ein Link drin steht der als GET Parameter userId und token übergibt.

    Das bedeutet du brauchst jetzt noch ein PHP Skript das du z.B. activate.php nennst.
    Dieses Skript prüft dann das GET Array auf userId und token.
    Wenn die Parameter übergeben wurden, nimmst die Parameter und machst ne Abfrage an die Tabelle Aktivierungen und prüfst halt ob die Aktivierung existiert.
    Wenn ja, entfernst die Aktivierung und setzt in der Benutzertabelle z.B. ein Feld das sich activated nennt auf TRUE.
    Wenn nein, ist der Benutzer schon aktiviert oder vorher is iwas schief gelaufen... Is ja auch logisch.

    Ist zwar etwas Arbeit aber das ist alles eigentlich nur ne Frage der Logik.

    Dekompilieren brauch man so überhaupt nichts.
    @jmj
    Es tut mir leid, dass du dir den Aufwand gemacht hast, aber da hast du was falsch verstanden ;( . Wie ich den Vorgang umsetze verstehe ich ja und das habe ich auch getan, nur stelle ich mir die Frage wie man verhindern kann, dass jemand die register.php vollspammt indem er z.B. einfach den Usernamen hochzählt, vorrausgesetzt natürlich derjenige weiß wie er die register.php zu bedienen hat.

    Bsp.: Die Register-API nimmt Username, Passwort und Email entgegen. Der "Angreifer" spammt das jetzt einfach in einer Schleife:

    Quellcode

    1. register.php?user=test1&hash=<irgendein hash>&email=<irgendeine Wegwerfadresse>
    2. register.php?user=test2&hash=<irgendein hash>&email=<irgendeine Wegwerfadresse>
    3. register.php?user=test3&hash=<irgendein hash>&email=<irgendeine Wegwerfadresse>
    4. register.php?user=test4&hash=<irgendein hash>&email=<irgendeine Wegwerfadresse>
    5. usw...


    Wie lässt sich das verhindern, bzw. viele Requests pro Zeiteinheit von einem User abfangen?

    8-) faxe1008 8-)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „faxe1008“ ()

    Ich würde da auf die Performance des WebServers vertrauen und folgene Abwandlung von @jmj verwenden:
    Wenn sich jemand anmeldet/register.php aufruft, dann empfängt die Seite die Anmeldedaten. Sollte es KEINEN bestehenden (und vor allem verifizierten) Eintrag geben, dann schick die Aktivierungsmail. Wenn jedoch schon ein (verifizierter) Eintrag da ist, dann schick eine Mail an die Adresse, in der du dem Empfänger mitteilst, dass mit seinem Account ein erneuter Registrierungsprozess gestartet wurde.
    Wenn der (ahnungslose) Empfänger/Kunde 5k Mails bekommt, in denen drinnen steht, dass ein neuer Registrierungsprozess gestartet wurde, dann kann man im WebServer-Log nachsehen (falls die IP/der Hostname/Devicec/OS gelogged wurde), WER da so rum gespammed hat.

    Ganz ausschließen kann man da nix. (Also dass dich jemand mit Anfragen voll spammt)

    Oder: Wenn ein bereits vorhandener Account noch einmal angelegt wurde, dann halt eine Ausgabe machen, dass die Anmeldung fehlgeschlagen ist.

    Summa summarum: ENTWEDER bekommst Du die Massen an Anfragen ab UND schickst eine Meldung an den Kunden raus ODER Du schluckst die Anfragen alleine UND schickst nix weiter. In jedem Fall bist du zumindest hinsichlich der Anfragen der Gelackmeierte.
    Lg Radinator

    Edit:

    faxe1008 schrieb:

    vollspammt indem er z.B. einfach den Usernamen hochzählt
    Naja, ganz einfach. Indem du den Account, wenn er angefragt wird, in einer temporären Tabelle anlegst und erst wenn er verifiziert wird in die Datenbank, die du real auch verwendest, übertragen. Ich empfehle deswegen eine temporäre DB, da du - wenn dir etwa der Counter ausgeht, einfach die Einträge, die nicht verifiziert sind (und älter, als 2 Tage sind), rausschmeißen kannst. Wenn sich jemand verifiziert, kannst du den Eintrag auch rauswerfen.
    Dann halt die DB re-organisieren und du sparst auch noch Speicherplatz
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Radinator“ ()

    Ich weiß nicht inwiefern das legal ist, weil ich mich da nicht auskenne, aber du könntest bei einem Registrierungsprozess (zumindest tempörär) für ne bestimmte Zeit die IP des Benutzers speichern und somit verhindern, das er dir mit Registrierungen die Datenbank zuspamt.

    Die IP kannst du in PHP ganz einfach so kriegen:

    PHP-Quellcode

    1. <?php print $_SERVER["REMOTE_ADDR"]; ?>


    D.h. die Aktivierungstabelle ergänzt du einfach noch mit nem Feld IP und bei ner neuen Registrierung prüfst du ob mit der selben IP schon ein Eintrag enstanden ist in den letzten z.B. 10 Minuten.

    Rechtsberatung ist hier verboten und ich sag auch ganz eindeutig das ich keine Ahnung hab, ob es legal ist IP Adressen zumindest temporär zu speichern.
    Habe ein Event eingerichtet, dass jede Stunde unaktivierte Nutzer löscht. Soweit so gut funktioniert auch alles nur hätte ich eine Stilfrage bezüglich der Antworten der API. Ich will das Resultat als JSON zurückgeben, da es sehr einfach ist das auszuwerten, nur ist die Frage, wie ich die Antworten vernüftig formatiere, sprich wie gestalte ich die Rückgabewerte?

    Momentan sieht die Rückgabe so aus:

    Quellcode

    1. {"Status Login" : "Success"}


    Das ist allerdings auf Dauer sehr frickelig, besonders wenn man die Fehlermeldungen detaillierter oder mehrsprachig machen möchte z.B. bei der Registrierung der Hinweiß, dass der Username bereits belegt ist anstatt einfach Error usw.

    Wie würdet ihr das gestalten, so dass der Wartungsaufwand und die Verwendung der Resultate in der App am komfortabelsten ist?

    8-) faxe1008 8-)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „faxe1008“ ()

    Tja, das ist was ich meine mit der Komplexität deines Projektes.

    Wenn es jetzt um mehrsprachigkeit geht, wäre ein Framework dafür sicherlich die bessere Wahl.
    Um sowas selbst machen zu können musst du dir halt ein bisschen was einfallen lassen.

    Du könntest z.B. einen optionalen POST Parameter lang mitübergeben der die Sprache angibt. Und dann prüfst du im PHP Script einfach, ob der Parameter gesetzt ist, wenn ja prüfst du mit dem Wert des Parameters ob du eine Übersetzung für diese Sprache hast. Wenn nicht, wird halt die Standard-Sprache ausgegeben.

    Ich würd' mir außerdem für die Formatierung ein kleines Format ausdenken.

    Zum Beispiel ein Feld success das immer bei jeder API Anfrage die du machst jeweils true oder false zurückgibt. Damit kannst du clientseitig dann direkt wissen, ob die Abfrage erfolgreich war, oder irgendwelche Parameter fehlen/fehlerhaft sind.

    Wenn z.B. eine Abfrage fehlerhaft ist, kannst du dir ja selbst definieren das dann auch immer ein error_code oder sowas in der Art ausgegeben wird (natürlich in der richtiges Sprache dann.)

    Ansonsten bau dir die JSON Strings einfach mit den Eigenschaften zusammen wie du sie brauchst und lass dir hiermit die Klassen generieren.
    Dann hast du das ganze auch vernünftig gekapselt.

    Edit: Ich hab' noch nie mit einem solchen REST Service Framework gearbeitet deshalb kann ich dir auch nicht sagen ob und was da alles möglich ist, aber ich bin mir ziemlich sicher das sich sowas dort relativ einfach gestalten lässt.
    Ich bin aber selbst auch ein Fan davon, das Rad neu zu erfinden, einfach weil's mir Spaß macht und ich so auch viel dazu lerne. Es ist halt mehr Arbeitsaufwand.

    faxe1008 schrieb:

    Das ist allerdings auf Dauer sehr frickelig, besonders wenn man die Fehlermeldungen detaillierter oder mehrsprachig machen möchte
    Was du machen könntest, ist dir als Rückgabewert (JSON) einen komplexen Typen erzeugen, der dir gleich schon im RootElement angibt, ob es eine reguläre Anmeldung ist, oder ob ein Fehler aufgetreten ist. Falls ein Fehler aufgetreten ist, dann greife auf das Element Error zu, wenn alles glatt läuft, dann ist das Element Error halt ne null-Referenz.

    faxe1008 schrieb:

    Wie würdet ihr das gestalten
    Was genau jetzt? Ich frage deswegen, weil es sich hier mittlerweile um 2 Baustellen handelt: Einmal das mit dem Reponse und einmal das mit den Email verschicken.

    jmj schrieb:

    das Rad neu zu erfinden
    Dafür haben wir ja schon wen: @ErfinderDesRades ;D
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell