0

What is required to log into a website using Jsoup? I believe my code is correct, but I have never successfully logged into a website using Jsoup so I might be missing something. Here is my code:

 try {                                            
        String url = ("http://quadrigacx.com/login");


        Connection.Response loginForm = (Connection.Response)Jsoup.connect(url)
                    .method(Connection.Method.GET)
                    .execute();





        Document loginDoc = loginForm.parse();


        Elements loginElements = loginDoc.select("input:not([name=client_id]):not([name=password])");

        int i = 0;

        String v[] = new String[loginElements.size()];

        for (Element element: loginElements){
            v[i++] = element.attr("value");
        }


        int ii = 0;

        String n[] = new String[loginElements.size()];

        for (Element element: loginElements){
            n[ii++] = element.attr("name");
        }


         Connection.Response loginFormLogin = (Connection.Response)Jsoup.connect(url)
                 .cookies(loginForm.cookies())          
                .data(n[0],v[0])
                 .data("client_id", "xxxxxxx")
                 .data("password", "xxxxxx")
                .data(n[1],v[1])
                .data(n[2],v[2])
                 .method(Connection.Method.POST)
                 .execute();


         Document document2 = Jsoup.connect("http://quadrigacx.com/settings")
            .cookies(loginFormLogin.cookies())
            .get();
        System.out.print(document2.toString());
    } catch (IOException ex) {
        Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
    }

document2 returns a login page which shows it didn't successfully log in. There is a input value named time, and I think that it might be why it doesn't work. It is a value that goes up over time; I ran the code twice and the time variables returned 1511226860 and 1511226876. My code takes about 10 seconds to print the doc, so maybe the time variable has already changed by the time it sends the post request? I am not sure whether this is the problem. Maybe there is something else I'm not seeing? Thanks.

Edit: Here is the code, I post the authenticate after I have already logged in with the user Id and password. loginCookies are the cookies from the first login. Connection.Response auth = Jsoup.connect("https://quadrigacx.com/authenticate") .userAgent("Mozilla") .method(Connection.Method.POST) .cookies(loginCookies) .data("google_code", googleCode.getText()) .data("email_code", emailCode.getText()) .data("authenticate", "Authenticate") .followRedirects(true) .execute(); I have also tried: byte[] gcText = googleCode.getText().getBytes(ISO_8859_1); String gcValue = new String(gcText, UTF_8); byte[] ecText = emailCode.getText().getBytes(ISO_8859_1); String ecValue = new String(ecText, UTF_8); Connection.Response auth = Jsoup.connect("https://quadrigacx.com/authenticate") .userAgent("Mozilla") .method(Connection.Method.POST) .cookies(loginCookies) .data("google_code", gcValue) .data("email_code", ecValue) .data("authenticate", "Authenticate") .followRedirects(true) .execute();

sandra burgle
  • 47
  • 1
  • 8
  • The password is not being sent "as-is" to the server. Open the dev-tools of the browser and you'll see that it is hashed/encrypted in some way, so you'll have to do some reversing to figure the proccess and imitate it. I would start with the scripts named SHA256 and QCX. Another option is to check wheater the site has an API. – TDG Nov 21 '17 at 17:39
  • I did not find the namedcalled SHA256, but I found this `$(document).ready(function(){ if (clientId && pword) $('#password').val(QCX.security.hash(clientId, pword)); else return false; ` in the submit script, does that mean the client id is also hashed? – sandra burgle Nov 21 '17 at 18:31
  • @TDG In a case like this, I think it would be easier if I were able to log in manually on my browser, and then copy the cookies + userAgent into my program and start from there. Is that possible? – sandra burgle Nov 21 '17 at 19:00

1 Answers1

1

You need to add more parameters to your request: csrf, time, hash

Code with empty TABLE:

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

public class Quadrigacx {
    public static String[] TABLE = new String[]{}; // Add data here

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {

        final String URL = "https://www.quadrigacx.com/login/";
        String password = "password";
        String clientId = "id";

        String hashPassword = getHash(new String[]{clientId, password});

        Connection.Response response = Jsoup.connect(URL)
                .userAgent("Mozilla")
                .method(Connection.Method.GET)
                .execute();

        Element csrf = response.parse().select("input[name=csrf]").first();
        Element time = response.parse().select("input[name=time]").first();
        Element hash = response.parse().select("input[name=hash]").first();

        Jsoup.connect(URL)
                .userAgent("Mozilla")
                .method(Connection.Method.POST)
                .cookies(response.cookies())
                .data("password", hashPassword)
                .data("client_id", clientId)
                .data("csrf", csrf.attr("value"))
                .data("time", time.attr("value"))
                .data("hash", hash.attr("value"))
                .execute();

        String googleCode = "";

        while (!googleCode.matches("^(?=[0-9]+)\\d{6}$")) {
            System.out.print("Please enter the Two-Factor Authentication to validate your login. (Numbers Only): ");
            Scanner in = new Scanner(System.in);
            googleCode = in.nextLine();
        }

        Jsoup.connect("https://www.quadrigacx.com/authenticate")
                .userAgent("Mozilla")
                .method(Connection.Method.POST)
                .cookies(response.cookies())
                .data("google_code", googleCode)
                .data("redirect", "dash")
                .data("authenticate", "Authenticate")
                .execute();

        response = Jsoup.connect("https://www.quadrigacx.com/dash/")
                .userAgent("Mozilla")
                .cookies(response.cookies())
                .method(Connection.Method.GET)
                .execute();

        System.out.println(response.body());

    }

    private static String getHash(String[] loginArray) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        StringBuilder h = new StringBuilder();
        for (String data : loginArray)
            h.append(data).append(getSalt(data));

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] byteHash = digest.digest(h.toString().getBytes(StandardCharsets.UTF_8));

        StringBuilder sb = new StringBuilder(byteHash.length * 2);
        for (byte b : byteHash)
            sb.append(String.format("%02x", b));

        return sb.toString();
    }

    private static String getSalt(String arg) throws UnsupportedEncodingException {
        return TABLE[getLastByte(arg)];
    }

    private static int getLastByte(String login) throws UnsupportedEncodingException {
        final byte[] utf8Bytes = login.getBytes("UTF-8");
        return utf8Bytes[utf8Bytes.length - 1];
    }
}

Full working code you can find here (very long):

https://pastebin.com/aBf1M3fX

Community
  • 1
  • 1
Sestertius
  • 1,367
  • 1
  • 14
  • 13
  • Thanks for the code it is working nice, now I am trying to log in using their "Two-Factor Authentication" service. I did some digging and found this `
    ` Does this mean I have to convert the google and email codes to utf 8? I'll update my code my code so you can see.
    – sandra burgle Nov 24 '17 at 02:18
  • Thanks for the help, may I ask what `!gCode.matches("^(?=[0-9]+)\\d{6}$")` means? I would like to have a better understanding in case I can use the same method for getting the emailCode aswell. Thanks! – sandra burgle Nov 25 '17 at 02:04
  • I did some research and I am guessing it means "if the code is not 6 digit long and contains number from 1-9". I have another question though, can the input values for emailCode and googleCode be passed just as strings or do I have to do some utf-8 conversion kind of like what you did for the password field? – sandra burgle Nov 25 '17 at 02:19