Overestimating on purpose isn't the right way either, and not just for ethical reasons. Finishing early makes the client think you cheated them, and actually working the whole time makes you think you cheated yourself. Especially if you end up having underestimated after all.
And changes? Ugh. Clients truly don't understand why X is harder than Y, and they think it should cost the same.
I've been pretty successful in the past at guiding management into solutions that are easy to code and maintain, rather than the nightmare they asked for, but having to explain all that to a new client each time would be too much.