To debounce correctly, you must measure time in some way and you can do two things:
Ensure that a certain thing is stable (this is not actually debouncing). For example, if your button had long wires, you could be worried of noises which could pollute the signal in. So you read the signal one time, and then a second time a little later, to check that the signal is still there and it was not noise. Perfect would be to monitor the signal for a period of time and, only if the signal didn't change in that period of time, take it as valid.
Proper debouncing. When a signal from inactive state goes to active, you must ignore shorts falls (active-inactive-active) of the signal.
Your button gives you a low level when pressed, and you can ignore the noise. So, as soon the signal goes low, you know the button has been pressed. This is the perfect scenario for an interrupt. But, if the button bounces, it will lower and rise the signal very quickly - too much quickly for a human being, but not too much for an MCU. What you have to do is to ignore further "pressures" for a while, for example 1 millisecond, or 5, or 1/100 of a second, or so. Then, you have to count time (another interrupt, presumably).
Suppose you have an interrupt routine that fires every millisecond. In that routine, decrement a counter (if it is > 0). When the button is pressed, and the counter is zero, accept the button press and set the counter to a value. Further pressures of the button will be ignored, until the counter will "slowly" decay to zero thanks to the other routine (in interrupt) which measures time.
This is just an idea, there are many many ways to do just the same or even better (noise canceling).
In your case, you could also just sleep() (or do a delay loop) inside the interrupt routine you already have (not beautiful), or disable that interrupt for a given time (so you must measure time).