cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

How to make this not dangerous?

from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "pass"))

def add_friend(tx, name, friend_name):
    tx.run("MERGE (a:Person {name: $name}) "
           "MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
           name=name, friend_name=friend_name)

def print_friends(tx, name):
    for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
                         "RETURN friend.name ORDER BY friend.name", name=name):
        print(record["friend.name"])

def dictToProperties(properties_dict):
    props = ""
    for key in properties_dict:
        props += key
        props += ': '
        props += '\''
        props += properties_dict[key]
        props += '\''
        props += ', '
    return props[:-2]

def add_node(tx, labels, properties):
    tx.run("CREATE (" + ':'.join(labels) + " {" + dictToProperties(properties) + "}) ")

props = {'name': '\' }) \nWITH true as pass\nMATCH (e) DETACH DELETE e RETURN ({e: \''}
print(dictToProperties(props))

with driver.session() as session:
    session.write_transaction(add_friend, "Arthur", "Guinevere")
    session.write_transaction(add_friend, "Arthur", "Lancelot")
    session.write_transaction(add_friend, "Arthur", "Merlin")
    session.write_transaction(add_node, ['Person', 'Swedish'], props)
    session.read_transaction(print_friends, "Arthur") # (nothing to print)

driver.close()

The neo4j python driver provides this sort of "injection" protection, right ?
I wish it provided this kind of idiomatic function (add_node) that I'm trying to implement.

3 REPLIES 3

MuddyBootsCode
Graph Steward

Hello Wis, welcome to the community. What do you mean by make this not dangerous? You're correct it's not possible to dynamically create nodes in the graph the way that you're trying to do, but that's probably for the best from a schema integrity point of view. In my experience it helps to know exactly what transactions are being run, etc.

Hi @MuddyBootsCode sorry for not being clear.
look at the value of name in the props dictionary, it causes what is commonly/popularly known as an "sql injection".
it's possible, but I agree with you it may not be good practice and that you need a schema model in code, preferably with an Object Graph Mapper (OGM).

for now I think I fixed it by making it return the records in the query and the method, like so:

def add_node(tx, labels, properties):
    return tx.run(
        "CREATE (p:"
        + ":".join(labels)
        + " {"
        + dictToProperties(properties)
        + "}) RETURN p"
    )

now the parser returns this error with a python exception that I can catch:

neobolt.exceptions.CypherSyntaxError: RETURN can only be used at the end of the query (line 3, column 27 (offset: 83))
"MATCH (e) DETACH DELETE e RETURN ({e: ''}) RETURN p"

Ah, gotcha. Looks like you've got it figured out. Nice implementation.