Cesc Fabregas converted the decisive spot-kick in Donetsk, firing his shot in off the post to send Spain through after Bruno Alves had hit the bar for Portugal.
Earlier, Cristiano Ronaldo had missed a good chance to put Portugal through in the last minute of normal time while Portugal keeper Rui Patricio made superb saves to deny Jesus Navas and Andres Iniesta in extra-time.
The Spaniards had started better, and ought to have gone ahead from their first chance in the ninth minute when Manuel Negredo pulled the ball back for Alvaro Arbeloa to fire over the bar from the edge of the box.
Andres Iniesta blazed over from long range a minute later, but Portugal threatened in the 13th minute through Ronaldo, who beat Gerard Pique down the left before crossing towards Nani, with Iker Casillas jumping to make a crucial interception.
Paulo Bento’s men had clearly wrested the upper hand, suffocating the Spanish midfield and worrying their opponents through the persistent threat of Ronaldo and Nani up front.
But Spain still almost contrived the grab the lead against the run of play in the 29th minute, when Xavi’s clever ball found Iniesta on the edge of the box, who rolled the ball onto his right foot before floating a shot inches over Rui Patricio’s goal.
Within two minutes, Portugal had responded with an even better chance, Joao Moutinho’s persistence paying off on the edge of the box as he set free Ronaldo to drill a low shot just wide of Casillas left hand post.
Portugal’s control continued into the second half, with Nani almost picking out the head of Hugo Almeida from a dangerous right wing cross, and it proved enough for Vicente Del Bosque, who replaced Negredo with Fabregas up front.
Almeida wasted a good chance in the 58th minute when he fired ambitiously over the Spanish bar instead of picking out Ronaldo or Nani, who were unmarked to his left and right respectively.
Belatedly, Spain started to show signs of stirring, Xabi drilling a shot straight at Patricio from long range, but despite beginning to edge possession, chances continued to be few and far between.
Ronaldo, still terrorising the Spanish defenders at every opportunity, fired a free-kick just over from 30 yards, but a game that had started brightly drifted into a dull spell in which neither side could serve up much of a threat.
Then came a glorious chance for Ronaldo in the last minute of normal time, when a Portuguese counter-attack saw Raul Meireles feed the Real Madrid man who fired over the bar from the left side of the box.
The introduction of Pedro lent some urgency to the Spanish attack in extra-time, and his run set up a chance for Iniesta in the seventh minute of the extra half hour, but his low shot was blocked in the box.
The Portuguese were plainly tiring, and Spain had an even better chance in the 104th minute, when Jordi Alba’s cross found Iniesta in front of goal but Patricio managed to flap his shot wide from six yards.
Sergio Ramos slammed a long-range free-kick just over the bar before the end of the first period of extra-time, and Ramos was soon in critical action at the other end when cutting out a Fabio Coentrao ball meant for Ronaldo.
Substitute Jesus Navas was next to get the chance to break the deadlock in the 22nd minute of extra-time, picking up a ball from Arbeloa in the box and hitting a shot which Patricio did well to save down low.
As Spain kept pressing, Pedro briefly burst clear before being caught by Fabio Coentrao, but by then there was a certain inevitability about a match that promised much but offered little heading to penalties.
Alonso had the first spot-kick saved by Patricio but Casillas evened things up by saving the first Portuguese penalty from Moutinho.
Iniesta, Pepe, Pique, Nani and Sergio Ramos all put away their penalties before Alves – who had inadvertently stepped up for the previous penalty which was eventually converted by Nani – hit the bar, leaving Fabregas to put Spain through.